Initial commit
This commit is contained in:
548
skills/ctf-rev/SKILL.md
Normal file
548
skills/ctf-rev/SKILL.md
Normal file
@@ -0,0 +1,548 @@
|
||||
---
|
||||
name: ctf-rev
|
||||
description: Solve CTF reverse engineering challenges using systematic analysis to find flags, keys, or passwords. Use for crackmes, binary bombs, key validators, obfuscated code, algorithm recovery, or any challenge requiring program comprehension to extract hidden information.
|
||||
---
|
||||
|
||||
# CTF Reverse Engineering
|
||||
|
||||
## Purpose
|
||||
|
||||
You are a CTF reverse engineering solver. Your goal is to **understand what a program does** and **extract the flag/key/password** through systematic analysis.
|
||||
|
||||
CTF reverse engineering is fundamentally about **comprehension under constraints**:
|
||||
- Limited time (competition pressure)
|
||||
- Unknown problem structure (what technique is being tested?)
|
||||
- Minimal documentation (that's the challenge!)
|
||||
- Goal-oriented (find the flag, not perfect understanding)
|
||||
|
||||
Unlike malware analysis or vulnerability research, CTF reversing tests your ability to:
|
||||
1. **Quickly identify the core challenge** (crypto? obfuscation? algorithm recovery?)
|
||||
2. **Trace critical data flow** (where does input go? how is it validated?)
|
||||
3. **Recognize patterns** (standard algorithms, common tricks)
|
||||
4. **Adapt your approach** (static vs dynamic, top-down vs bottom-up)
|
||||
|
||||
## Conceptual Framework
|
||||
|
||||
### The Three Questions
|
||||
|
||||
Every reverse engineering challenge boils down to answering:
|
||||
|
||||
**1. What does the program EXPECT?**
|
||||
- Input format (string, number, binary data?)
|
||||
- Input structure (length, format, encoding?)
|
||||
- Validation criteria (checks, comparisons, constraints?)
|
||||
|
||||
**2. What does the program DO?**
|
||||
- Transformation (encrypt, hash, encode, compute?)
|
||||
- Comparison (against hardcoded value, derived value?)
|
||||
- Algorithm (standard crypto, custom logic, mathematical?)
|
||||
|
||||
**3. How do I REVERSE it?**
|
||||
- Is the operation reversible? (encryption vs hashing)
|
||||
- Can I brute force? (keyspace size, performance)
|
||||
- Can I derive the answer? (solve equations, trace backwards)
|
||||
- Can I bypass? (patch, debug, manipulate state)
|
||||
|
||||
### Understanding vs Solving
|
||||
|
||||
**You don't need to understand everything** - focus on what gets you to the flag:
|
||||
|
||||
**Full Understanding** (often unnecessary):
|
||||
- Every function's purpose
|
||||
- Complete program flow
|
||||
- All edge cases and error handling
|
||||
- Library implementation details
|
||||
|
||||
**Sufficient Understanding** (what you need):
|
||||
- Entry point to flag validation
|
||||
- Core transformation logic
|
||||
- Input-to-output relationship
|
||||
- Comparison or success criteria
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Program has 50 functions. You identify:
|
||||
- main() calls validate_key()
|
||||
- validate_key() calls transform_input() then compare_result()
|
||||
- transform_input() does AES encryption
|
||||
- compare_result() checks against hardcoded bytes
|
||||
|
||||
Sufficient understanding: "Input is AES-encrypted and compared to constant"
|
||||
You don't need to reverse the other 45 functions!
|
||||
```
|
||||
|
||||
## Core Methodologies
|
||||
|
||||
### Static Analysis: Code Comprehension
|
||||
|
||||
**Goal:** Understand program logic by reading decompiled/disassembled code
|
||||
|
||||
**When to use:**
|
||||
- Small, focused programs (crackmes, keygens)
|
||||
- Algorithm identification challenges
|
||||
- When dynamic analysis is hindered (anti-debugging, complex state)
|
||||
- When you need to understand transformation logic
|
||||
|
||||
**Approach:**
|
||||
1. **Find the critical path** - Entry point → flag validation → success
|
||||
2. **Trace input flow** - Where does user input go? How is it used?
|
||||
3. **Identify operations** - What transformations occur? (XOR, loops, comparisons)
|
||||
4. **Recognize patterns** - Does this match known algorithms? (see patterns.md)
|
||||
|
||||
**ReVa workflow:**
|
||||
```
|
||||
1. get-decompilation of entry/main function
|
||||
- includeIncomingReferences=true to see program structure
|
||||
|
||||
2. Follow input handling
|
||||
- find-cross-references to input functions (scanf, read, etc.)
|
||||
- Trace data flow from input to validation
|
||||
|
||||
3. Analyze transformations
|
||||
- rename-variables to clarify data flow
|
||||
- change-variable-datatypes to understand operations
|
||||
- set-decompilation-comment to document logic
|
||||
|
||||
4. Identify success criteria
|
||||
- Find comparison or validation logic
|
||||
- Extract expected values or patterns
|
||||
```
|
||||
|
||||
### Dynamic Analysis: Runtime Observation
|
||||
|
||||
**Goal:** Observe program behavior during execution
|
||||
|
||||
**When to use:**
|
||||
- Complex control flow (hard to follow statically)
|
||||
- Obfuscated or packed code
|
||||
- When you need to see intermediate values
|
||||
- Time-based or environmental checks
|
||||
|
||||
**Approach:**
|
||||
1. **Set breakpoints at key locations**
|
||||
- Input processing
|
||||
- Transformations
|
||||
- Comparisons
|
||||
- Success/failure branches
|
||||
|
||||
2. **Observe state changes**
|
||||
- Register/variable values
|
||||
- Memory contents
|
||||
- Function arguments/returns
|
||||
|
||||
3. **Test hypotheses**
|
||||
- "If I input X, does Y happen?"
|
||||
- "What value is being compared here?"
|
||||
|
||||
**Note:** ReVa focuses on static analysis. For dynamic analysis, use external debuggers (gdb, x64dbg, etc.)
|
||||
|
||||
### Hybrid Approach: Best of Both Worlds
|
||||
|
||||
**Most effective for CTF challenges**
|
||||
|
||||
**Workflow:**
|
||||
1. **Static: Identify structure** (find validation function, success path)
|
||||
2. **Dynamic: Observe runtime** (breakpoint at validation, see expected value)
|
||||
3. **Static: Understand transformation** (reverse the algorithm)
|
||||
4. **Dynamic: Verify solution** (test your derived key/flag)
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Static: "Input is transformed by function sub_401234 then compared"
|
||||
Dynamic: Run with test input, breakpoint at comparison → see expected value
|
||||
Static: Decompile sub_401234 → recognize as base64 encoding
|
||||
Solve: base64_decode(expected_value) = flag
|
||||
Dynamic: Verify flag works
|
||||
```
|
||||
|
||||
## Problem-Solving Strategies
|
||||
|
||||
### Strategy 1: Top-Down (Goal-Oriented)
|
||||
|
||||
**Start from the win condition, work backwards**
|
||||
|
||||
**When to use:**
|
||||
- Clear success/failure indicators (prints "Correct!" or "Wrong!")
|
||||
- Simple program structure
|
||||
- When you want to understand the minimum necessary
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
1. Find success message/function
|
||||
2. find-cross-references direction="to" → What calls this?
|
||||
3. get-decompilation of validation function
|
||||
4. Identify what conditions lead to success
|
||||
5. Work backwards to understand required input
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
1. String "Congratulations!" at 0x402000
|
||||
2. Referenced by function validate_flag at 0x401500
|
||||
3. Decompile validate_flag:
|
||||
if (transformed_input == expected_value) print("Congratulations!");
|
||||
4. Now focus on: What's expected_value? How is input transformed?
|
||||
```
|
||||
|
||||
### Strategy 2: Bottom-Up (Data Flow)
|
||||
|
||||
**Start from input, trace forward to validation**
|
||||
|
||||
**When to use:**
|
||||
- Complex program structure (many functions)
|
||||
- When win condition is unclear
|
||||
- When you want to understand transformations
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
1. search-strings-regex pattern="(scanf|read|fgets|input)"
|
||||
2. find-cross-references to input function
|
||||
3. Trace data flow: input → storage → transformation → usage
|
||||
4. Follow transformations until you reach comparison/validation
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
1. scanf at 0x401000 reads into buffer
|
||||
2. buffer passed to process_input(buffer)
|
||||
3. process_input calls encrypt(buffer, key)
|
||||
4. Encrypted result compared to hardcoded bytes
|
||||
5. Now analyze: What's the encryption? Can we reverse it?
|
||||
```
|
||||
|
||||
### Strategy 3: Pattern Recognition
|
||||
|
||||
**Identify standard algorithms or common techniques**
|
||||
|
||||
**When to use:**
|
||||
- Crypto challenges (encryption, hashing)
|
||||
- Encoding challenges (base64, custom encodings)
|
||||
- Algorithm implementation challenges
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
1. Look for algorithmic patterns (see patterns.md):
|
||||
- Loop structures (rounds, iterations)
|
||||
- Constant arrays (S-boxes, tables)
|
||||
- Characteristic operations (XOR, rotations, substitutions)
|
||||
|
||||
2. Compare to known implementations:
|
||||
- read-memory at constant arrays → compare to standard tables
|
||||
- Count loop iterations → indicates algorithm variant
|
||||
- search-decompilation for crypto patterns
|
||||
|
||||
3. Once identified, apply standard solutions:
|
||||
- AES → decrypt with known/derived key
|
||||
- RC4 → decrypt with extracted key
|
||||
- Custom XOR → reverse the XOR operation
|
||||
```
|
||||
|
||||
### Strategy 4: Constraint Solving
|
||||
|
||||
**Frame the problem as mathematical constraints**
|
||||
|
||||
**When to use:**
|
||||
- Serial/key validation (input must satisfy equations)
|
||||
- Mathematical puzzles
|
||||
- Multiple related checks
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
1. Identify all constraints on input:
|
||||
input[0] + input[1] == 0x42
|
||||
input[0] ^ input[2] == 0x13
|
||||
input[1] * 2 == input[3]
|
||||
|
||||
2. Extract to external solver (z3, constraint solver)
|
||||
|
||||
3. Solve for input values
|
||||
|
||||
4. Verify solution in program
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Decompiled validation:
|
||||
if (flag[0] + flag[1] != 100) return 0;
|
||||
if (flag[0] - flag[1] != 20) return 0;
|
||||
if (flag[2] ^ 0x42 != 0x33) return 0;
|
||||
|
||||
Solve:
|
||||
flag[0] + flag[1] = 100
|
||||
flag[0] - flag[1] = 20
|
||||
→ flag[0] = 60, flag[1] = 40
|
||||
|
||||
flag[2] ^ 0x42 = 0x33
|
||||
→ flag[2] = 0x33 ^ 0x42 = 0x71 = 'q'
|
||||
```
|
||||
|
||||
## Flexible Workflow
|
||||
|
||||
CTF challenges vary widely - adapt your approach:
|
||||
|
||||
### Initial Assessment (5-10 minutes)
|
||||
|
||||
**Understand the challenge:**
|
||||
- What's provided? (binary, source, description?)
|
||||
- What's the goal? (find flag, generate key, bypass check?)
|
||||
- What's the constraint? (time limit, black box?)
|
||||
|
||||
**ReVa reconnaissance:**
|
||||
```
|
||||
1. get-current-program or list-project-files
|
||||
2. get-strings-count and sample strings (100-200)
|
||||
- Look for: flag format, hints, library names
|
||||
3. get-symbols with includeExternal=true
|
||||
- Check for suspicious imports (crypto APIs, anti-debug)
|
||||
4. get-function-count to gauge complexity
|
||||
```
|
||||
|
||||
### Focused Investigation (15-45 minutes)
|
||||
|
||||
**Follow the most promising lead:**
|
||||
|
||||
**If you found flag format in strings:**
|
||||
→ Top-down from flag string
|
||||
|
||||
**If you found crypto APIs:**
|
||||
→ Pattern recognition (identify algorithm)
|
||||
|
||||
**If you found input validation:**
|
||||
→ Data flow tracing (input to validation)
|
||||
|
||||
**If program is simple (< 10 functions):**
|
||||
→ Comprehensive static analysis
|
||||
|
||||
**If program is complex or obfuscated:**
|
||||
→ Hybrid approach (dynamic to find key points, static to understand)
|
||||
|
||||
### Solution Extraction (10-20 minutes)
|
||||
|
||||
**Once you understand the mechanism:**
|
||||
|
||||
1. **Can you reverse it?**
|
||||
- Decryption, decoding, mathematical inverse
|
||||
|
||||
2. **Can you derive it?**
|
||||
- Solve constraints, extract from comparison
|
||||
|
||||
3. **Can you brute force it?**
|
||||
- Small keyspace, fast validation
|
||||
|
||||
4. **Can you bypass it?**
|
||||
- Patch comparison, manipulate state
|
||||
|
||||
**Verify your solution:**
|
||||
- Test with actual program (if possible)
|
||||
- Check flag format (usually flag{...} or CTF{...})
|
||||
|
||||
## Pattern Recognition
|
||||
|
||||
CTF challenges often test recognition of standard patterns. See `patterns.md` for detailed guides on:
|
||||
|
||||
**Cryptographic Patterns:**
|
||||
- Block ciphers (AES, DES, custom)
|
||||
- Stream ciphers (RC4, custom)
|
||||
- Hash functions (MD5, SHA, custom)
|
||||
- XOR obfuscation
|
||||
|
||||
**Algorithm Patterns:**
|
||||
- Encoding schemes (base64, custom alphabets)
|
||||
- Mathematical operations (modular arithmetic, matrix operations)
|
||||
- State machines (input validation via states)
|
||||
|
||||
**Code Patterns:**
|
||||
- Input validation loops
|
||||
- Character-by-character comparisons
|
||||
- Transformation + comparison structures
|
||||
- Anti-debugging tricks (for CTF context)
|
||||
|
||||
**Data Structure Patterns:**
|
||||
- Lookup tables (substitution ciphers)
|
||||
- Hardcoded arrays (expected values)
|
||||
- Buffer transformations
|
||||
|
||||
## ReVa Tool Usage for CTF
|
||||
|
||||
### Discovery Tools
|
||||
|
||||
**Find the interesting parts quickly:**
|
||||
|
||||
```
|
||||
search-strings-regex pattern="(flag|key|password|correct|wrong|success)"
|
||||
→ Find win/lose conditions
|
||||
|
||||
search-decompilation pattern="(scanf|read|input|strcmp|memcmp)"
|
||||
→ Find input/comparison functions
|
||||
|
||||
get-functions-by-similarity searchString="check"
|
||||
→ Find validation functions
|
||||
```
|
||||
|
||||
### Analysis Tools
|
||||
|
||||
**Understand the core logic:**
|
||||
|
||||
```
|
||||
get-decompilation with includeIncomingReferences=true, includeReferenceContext=true
|
||||
→ Get full context of validation logic
|
||||
|
||||
find-cross-references direction="both" includeContext=true
|
||||
→ Trace data flow and function relationships
|
||||
|
||||
read-memory to extract constants, tables, expected values
|
||||
→ Get hardcoded comparison targets
|
||||
```
|
||||
|
||||
### Improvement Tools
|
||||
|
||||
**Make code readable as you work:**
|
||||
|
||||
```
|
||||
rename-variables to track data flow
|
||||
→ input_buffer, encrypted_data, expected_hash
|
||||
|
||||
change-variable-datatypes to clarify operations
|
||||
→ uint8_t* for byte buffers, uint32_t for crypto state
|
||||
|
||||
set-decompilation-comment to document findings
|
||||
→ "AES round function", "Compares against flag"
|
||||
|
||||
set-bookmark for important locations
|
||||
→ type="Analysis" for key findings
|
||||
→ type="TODO" for things to investigate
|
||||
```
|
||||
|
||||
## Key Principles
|
||||
|
||||
### 1. Goal Focus
|
||||
**Don't analyze everything - focus on getting the flag**
|
||||
- Identify critical path (input → validation → success)
|
||||
- Ignore unrelated functions
|
||||
- Sufficient understanding > complete understanding
|
||||
|
||||
### 2. Adapt Quickly
|
||||
**Switch strategies if stuck**
|
||||
- Static not working? Try dynamic
|
||||
- Too complex? Look for simpler approach (bypass, brute force)
|
||||
- Pattern not matching? Could be custom algorithm
|
||||
|
||||
### 3. Leverage Knowledge
|
||||
**CTF challenges reuse concepts**
|
||||
- Standard crypto algorithms
|
||||
- Common obfuscation tricks
|
||||
- Typical validation patterns
|
||||
- Recognize and apply known solutions
|
||||
|
||||
### 4. Document Progress
|
||||
**Track what you learn**
|
||||
```
|
||||
set-bookmark type="Analysis" category="Finding"
|
||||
→ Document what you've confirmed
|
||||
|
||||
set-bookmark type="TODO" category="Investigate"
|
||||
→ Track unanswered questions
|
||||
|
||||
set-decompilation-comment
|
||||
→ Preserve understanding for later reference
|
||||
```
|
||||
|
||||
### 5. Verify Incrementally
|
||||
**Test your understanding as you go**
|
||||
- "If this is AES, I should see S-box constants" → Check
|
||||
- "If input is XORed with 0x42, output[0] should be..." → Verify with example
|
||||
- "If this is the flag comparison, changing this byte should..." → Test hypothesis
|
||||
|
||||
## Common CTF Challenge Types
|
||||
|
||||
### Crackme / Serial Validation
|
||||
**Challenge:** Find input that passes validation
|
||||
**Approach:** Data flow tracing (input → validation logic)
|
||||
**Key insight:** Focus on validation function, extract constraints
|
||||
|
||||
### Algorithm Recovery
|
||||
**Challenge:** Implement or reverse unknown algorithm
|
||||
**Approach:** Pattern recognition, understand operations
|
||||
**Key insight:** Look for mathematical patterns, trace transformations
|
||||
|
||||
### Crypto Challenge
|
||||
**Challenge:** Decrypt ciphertext or find key
|
||||
**Approach:** Identify algorithm, extract key/IV, decrypt
|
||||
**Key insight:** Recognize standard crypto patterns (see patterns.md)
|
||||
|
||||
### Code Obfuscation
|
||||
**Challenge:** Understand obfuscated/packed code
|
||||
**Approach:** Dynamic analysis to observe deobfuscated state
|
||||
**Key insight:** Let program do the work, observe result
|
||||
|
||||
### Binary Bomb
|
||||
**Challenge:** Defuse "bomb" by providing correct inputs for each phase
|
||||
**Approach:** Phase-by-phase analysis, mixed static/dynamic
|
||||
**Key insight:** Each phase typically tests different concept
|
||||
|
||||
### Custom Encoding
|
||||
**Challenge:** Decode encoded flag or encode input correctly
|
||||
**Approach:** Identify encoding scheme, reverse or replicate
|
||||
**Key insight:** Look for transformation loops, character mappings
|
||||
|
||||
## Integration with Other Skills
|
||||
|
||||
### After Binary Triage
|
||||
**Triage identified suspicious areas → Deep dive with CTF focus**
|
||||
|
||||
```
|
||||
From triage bookmarks:
|
||||
- "Crypto function at 0x401234" → Identify algorithm, extract key
|
||||
- "Input validation at 0x402000" → Understand constraints, solve
|
||||
- "Suspicious string XOR" → Decode to find flag or hint
|
||||
```
|
||||
|
||||
### Using Deep Analysis
|
||||
**When you need detailed function understanding**
|
||||
|
||||
```
|
||||
CTF skill identifies: "Validation at validate_key function"
|
||||
Deep analysis answers: "What exactly does validate_key do?"
|
||||
CTF skill uses result: Apply findings to extract flag
|
||||
```
|
||||
|
||||
**Workflow:**
|
||||
1. CTF skill: High-level strategy, identify critical functions
|
||||
2. Deep analysis: Detailed investigation of specific functions
|
||||
3. CTF skill: Synthesize findings, extract solution
|
||||
|
||||
## Success Criteria
|
||||
|
||||
**You've solved the challenge when you can:**
|
||||
|
||||
1. **Demonstrate understanding:**
|
||||
- Explain how input becomes output
|
||||
- Identify the validation mechanism
|
||||
- Recognize the core algorithm/technique
|
||||
|
||||
2. **Extract the solution:**
|
||||
- Provide the flag/key/password
|
||||
- Explain how you derived it
|
||||
- Verify it works (if testable)
|
||||
|
||||
3. **Document the path:**
|
||||
- Key functions and addresses
|
||||
- Critical transformations or comparisons
|
||||
- Solution method (reverse, derive, brute force, bypass)
|
||||
|
||||
## Remember
|
||||
|
||||
CTF reverse engineering is **problem-solving under constraints**:
|
||||
- You have limited time
|
||||
- You need sufficient, not perfect, understanding
|
||||
- The goal is the flag, not comprehensive analysis
|
||||
- Adapt your strategy based on what you find
|
||||
- Leverage patterns and prior knowledge
|
||||
- Switch between static and dynamic as needed
|
||||
|
||||
**Focus on answering:**
|
||||
1. What does the program expect? (input format/structure)
|
||||
2. What does the program do? (transformation/validation)
|
||||
3. How do I reverse it? (derive/decrypt/solve/bypass)
|
||||
|
||||
When you answer these three questions, you have your flag.
|
||||
906
skills/ctf-rev/patterns.md
Normal file
906
skills/ctf-rev/patterns.md
Normal file
@@ -0,0 +1,906 @@
|
||||
# CTF Reverse Engineering Pattern Recognition
|
||||
|
||||
This document provides pattern recognition guides for common CTF reverse engineering challenges. Focus on **identifying patterns quickly** to guide your solution strategy.
|
||||
|
||||
## Cryptographic Patterns
|
||||
|
||||
### Simple XOR Patterns
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Single-byte XOR:
|
||||
for (i = 0; i < len; i++)
|
||||
output[i] = input[i] ^ 0xKEY;
|
||||
|
||||
Multi-byte XOR (repeating key):
|
||||
for (i = 0; i < len; i++)
|
||||
output[i] = input[i] ^ key[i % keylen];
|
||||
|
||||
Rolling XOR:
|
||||
xor_val = seed;
|
||||
for (i = 0; i < len; i++) {
|
||||
output[i] = input[i] ^ xor_val;
|
||||
xor_val = next_value(xor_val); // Linear congruential or similar
|
||||
}
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Very short functions (5-15 lines decompiled)
|
||||
- XOR operation in loop
|
||||
- Constant value or small array
|
||||
- Modulo operation for key index (`i % keylen`)
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-decompilation pattern="\\^" caseSensitive=false
|
||||
→ Find XOR operations
|
||||
|
||||
get-decompilation of suspicious function
|
||||
→ Look for loop with XOR
|
||||
|
||||
read-memory at key location
|
||||
→ Extract XOR key
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- XOR is self-inverse: `decrypt(x) = encrypt(x)`
|
||||
- If you have ciphertext + key: plaintext = ciphertext XOR key
|
||||
- If you have plaintext + ciphertext: key = plaintext XOR ciphertext
|
||||
- If you have partial known plaintext: derive key, decrypt rest
|
||||
|
||||
### Base64 and Variants
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Character lookup table (64-character alphabet):
|
||||
Standard: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
|
||||
Custom: May use different alphabet
|
||||
|
||||
Bit manipulation:
|
||||
3 bytes → 4 encoded characters
|
||||
Shifting and masking: (data >> 18) & 0x3F
|
||||
|
||||
Padding:
|
||||
'=' characters or custom padding
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- 64-character string constant (lookup table)
|
||||
- Bit shifting: `>> 6`, `>> 12`, `>> 18`
|
||||
- Masking: `& 0x3F` (6 bits)
|
||||
- 3-to-4 or 4-to-3 byte conversion ratio
|
||||
- Padding logic
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-strings-regex pattern="[A-Za-z0-9+/]{64}"
|
||||
→ Find base64 alphabet
|
||||
|
||||
search-decompilation pattern="& 0x3f"
|
||||
→ Find 6-bit masking (base64 characteristic)
|
||||
|
||||
get-decompilation of encoding function
|
||||
→ Confirm 3→4 byte transformation
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- If standard base64: use standard decoder
|
||||
- If custom alphabet: map custom → standard, then decode
|
||||
- Reverse engineering: identify alphabet, implement decoder
|
||||
|
||||
### Block Cipher Patterns (AES, DES, etc.)
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
AES characteristics:
|
||||
- 128-bit (16-byte) blocks
|
||||
- 10, 12, or 14 rounds (for 128, 192, 256-bit keys)
|
||||
- S-box: 256-byte constant array starting 63 7c 77 7b f2 6b 6f c5...
|
||||
- Mix columns, shift rows operations
|
||||
- Key schedule expansion
|
||||
|
||||
DES characteristics:
|
||||
- 64-bit (8-byte) blocks
|
||||
- 16 rounds
|
||||
- Permutation tables (IP, FP, E, P, S-boxes)
|
||||
- Feistel structure (split, swap, repeat)
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
```
|
||||
Nested loops:
|
||||
for (round = 0; round < NUM_ROUNDS; round++)
|
||||
for (i = 0; i < BLOCK_SIZE; i++)
|
||||
state[i] = transform(state[i], key[round]);
|
||||
|
||||
Large constant arrays:
|
||||
uint8_t sbox[256] = {0x63, 0x7c, 0x77, ...};
|
||||
|
||||
Block processing:
|
||||
Fixed-size chunks (16 bytes for AES, 8 for DES)
|
||||
|
||||
Key schedule:
|
||||
Function deriving round keys from master key
|
||||
```
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-decompilation pattern="(for.*round|for.*0x10)"
|
||||
→ Find round loops
|
||||
|
||||
read-memory at constant arrays
|
||||
→ Compare first bytes to known S-boxes:
|
||||
AES: 63 7c 77 7b f2 6b 6f c5
|
||||
DES S1: 0e 04 0d 01 02 0f 0b 08
|
||||
|
||||
get-decompilation with focus on nested loops
|
||||
→ Count iterations (round count indicates key size)
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Identify algorithm by S-box or constants
|
||||
- Extract key from memory or key schedule
|
||||
- Use standard implementation to decrypt
|
||||
- For custom implementations, replicate in Python/C
|
||||
|
||||
### Stream Cipher Patterns (RC4, etc.)
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
RC4 characteristics:
|
||||
KSA (Key Scheduling Algorithm):
|
||||
for i = 0 to 255: S[i] = i
|
||||
for i = 0 to 255: swap S[i] with S[(S[i] + key[i % keylen]) % 256]
|
||||
|
||||
PRGA (Pseudo-Random Generation Algorithm):
|
||||
i = 0, j = 0
|
||||
while generating:
|
||||
i = (i + 1) % 256
|
||||
j = (j + S[i]) % 256
|
||||
swap(S[i], S[j])
|
||||
output = S[(S[i] + S[j]) % 256]
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
```
|
||||
State array initialization:
|
||||
for (i = 0; i < 256; i++) state[i] = i;
|
||||
|
||||
Swap operations:
|
||||
temp = arr[i];
|
||||
arr[i] = arr[j];
|
||||
arr[j] = temp;
|
||||
|
||||
Modulo arithmetic:
|
||||
(i + 1) % 256
|
||||
index & 0xFF (equivalent to % 256)
|
||||
|
||||
Simple XOR with keystream:
|
||||
output[i] = input[i] ^ keystream[i];
|
||||
```
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-decompilation pattern="(swap|temp.*=.*\\[)"
|
||||
→ Find array swap operations
|
||||
|
||||
get-decompilation of initialization
|
||||
→ Look for 0-255 loop filling array
|
||||
|
||||
find-cross-references to state array
|
||||
→ Trace usage through KSA and PRGA
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Extract key from initialization
|
||||
- Replicate KSA to generate initial state
|
||||
- Replicate PRGA to generate keystream
|
||||
- XOR ciphertext with keystream to decrypt
|
||||
|
||||
### Hash Function Patterns
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
MD5/SHA characteristics:
|
||||
- Fixed initialization vectors (magic constants)
|
||||
- Block processing (512 bits / 64 bytes)
|
||||
- Multiple rounds (64 for MD5/SHA-256, 80 for SHA-1)
|
||||
- Bitwise operations: rotations, XOR, AND, OR, NOT
|
||||
- Padding: append 0x80, then zeros, then length
|
||||
|
||||
Magic constants:
|
||||
MD5: 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
|
||||
SHA-1: adds 0xc3d2e1f0
|
||||
SHA-256: Eight 32-bit constants derived from square roots
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
```
|
||||
Characteristic constants:
|
||||
Search for 0x67452301 (MD5/SHA-1 IV)
|
||||
|
||||
Fixed round counts:
|
||||
for (round = 0; round < 64; round++) // MD5, SHA-256
|
||||
for (round = 0; round < 80; round++) // SHA-1
|
||||
|
||||
Bitwise rotation macros:
|
||||
ROTL(x, n) = (x << n) | (x >> (32-n))
|
||||
|
||||
Message schedule (W array):
|
||||
Expands 16 input words to 64/80 words
|
||||
|
||||
Padding logic:
|
||||
Append 0x80, zeros, then 64-bit length
|
||||
```
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-decompilation pattern="0x67452301"
|
||||
→ Find MD5/SHA initialization
|
||||
|
||||
read-memory at round constants
|
||||
→ Identify specific hash variant
|
||||
|
||||
get-decompilation of hash function
|
||||
→ Count rounds, identify structure
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Hash functions are one-way (cannot decrypt)
|
||||
- If you find hash of flag: need to brute force or use known input
|
||||
- If you find comparison: extract expected hash, try common flags
|
||||
- Check for weak hash (MD5, SHA-1) or short input (brute-forceable)
|
||||
|
||||
## Encoding Patterns
|
||||
|
||||
### Character Substitution
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Lookup table mapping:
|
||||
output[i] = table[input[i]];
|
||||
|
||||
Caesar cipher (shift):
|
||||
output[i] = (input[i] - 'A' + shift) % 26 + 'A';
|
||||
|
||||
Custom alphabet:
|
||||
const char* alphabet = "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba";
|
||||
output[i] = alphabet[input[i] - 'A'];
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Character array constants (alphabets, substitution tables)
|
||||
- Character-by-character processing loops
|
||||
- Range checks: `if (c >= 'A' && c <= 'Z')`
|
||||
- Arithmetic on character codes: `c - 'A'`, `c + shift`
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-strings-regex pattern="[A-Z]{26}"
|
||||
→ Find alphabet strings
|
||||
|
||||
search-decompilation pattern="(- 'A'|% 26)"
|
||||
→ Find character arithmetic
|
||||
|
||||
get-decompilation of encoding function
|
||||
→ Identify substitution pattern
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Extract substitution table or shift value
|
||||
- Build reverse mapping
|
||||
- Apply to encoded data
|
||||
|
||||
### Binary-to-Text Encodings
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Hex encoding:
|
||||
"0123456789abcdef"
|
||||
nibble_high = (byte >> 4) & 0xF;
|
||||
nibble_low = byte & 0xF;
|
||||
|
||||
Binary/ASCII:
|
||||
Converting to "01011010" strings
|
||||
|
||||
Custom encodings:
|
||||
Mapping bytes to multi-character sequences
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Hex digit strings
|
||||
- Bit extraction: `>> 4`, `& 0xF`, `& 1`
|
||||
- Character code generation loops
|
||||
- 1-to-2 or 1-to-8 byte expansion
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-decompilation pattern="(>> 4|& 0xf)"
|
||||
→ Find nibble extraction (hex encoding)
|
||||
|
||||
get-strings to find encoding alphabets
|
||||
→ Check for hex, binary digit strings
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Identify encoding scheme
|
||||
- Implement decoder
|
||||
- Apply to encoded flag
|
||||
|
||||
## Input Validation Patterns
|
||||
|
||||
### Character-by-Character Comparison
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Direct comparison:
|
||||
for (i = 0; i < len; i++)
|
||||
if (input[i] != expected[i])
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
Comparison with transformation:
|
||||
for (i = 0; i < len; i++)
|
||||
if (transform(input[i]) != expected[i])
|
||||
return 0;
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Loop over input length
|
||||
- Comparison inside loop: `!=`, `==`
|
||||
- Early return on mismatch
|
||||
- Success after full loop completion
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-decompilation pattern="(if.*!=|if.*==)"
|
||||
→ Find comparison operations
|
||||
|
||||
get-decompilation of validation function
|
||||
→ Identify loop structure
|
||||
|
||||
read-memory at expected value array
|
||||
→ Extract expected bytes
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- If direct comparison: read expected array, that's the flag
|
||||
- If transformed comparison: reverse transformation
|
||||
- If complex transformation: trace each character
|
||||
|
||||
### Checksum Validation
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Sum check:
|
||||
sum = 0;
|
||||
for (i = 0; i < len; i++)
|
||||
sum += input[i];
|
||||
return (sum == EXPECTED_SUM);
|
||||
|
||||
XOR check:
|
||||
xor = 0;
|
||||
for (i = 0; i < len; i++)
|
||||
xor ^= input[i];
|
||||
return (xor == EXPECTED_XOR);
|
||||
|
||||
Custom accumulation:
|
||||
result = SEED;
|
||||
for (i = 0; i < len; i++)
|
||||
result = (result * MULT + input[i]) % MOD;
|
||||
return (result == EXPECTED);
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Accumulator variable (sum, product, xor)
|
||||
- Loop updating accumulator
|
||||
- Final comparison to constant
|
||||
- May be combined with other checks
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-decompilation pattern="(\\+=|\\*=|\\^=)"
|
||||
→ Find accumulator updates
|
||||
|
||||
get-decompilation of validation
|
||||
→ Identify accumulation pattern
|
||||
|
||||
read-memory at expected value
|
||||
→ Extract target checksum
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Single checksum: underconstrained (many solutions)
|
||||
- Multiple checksums: may uniquely identify input
|
||||
- Extract all constraints, solve as system of equations
|
||||
|
||||
### Constraint-Based Validation
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Multiple independent checks:
|
||||
if (input[0] + input[1] != 0x64) return 0;
|
||||
if (input[0] - input[1] != 0x14) return 0;
|
||||
if (input[2] ^ 0x42 != 0x33) return 0;
|
||||
if (input[3] * 2 == input[4]) return 0;
|
||||
return 1;
|
||||
|
||||
Relational constraints:
|
||||
if (input[i] != input[j] + 5) return 0;
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Multiple if-statements with comparisons
|
||||
- Arithmetic operations on input elements
|
||||
- Relationships between different input positions
|
||||
- Constants in comparisons
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
get-decompilation of validation function
|
||||
→ Identify all comparison statements
|
||||
|
||||
set-decompilation-comment on each constraint
|
||||
→ Document relationships
|
||||
|
||||
Extract to external solver:
|
||||
→ List all constraints, solve with z3 or similar
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Extract all constraints
|
||||
- Frame as system of equations
|
||||
- Solve using constraint solver (z3, SMT)
|
||||
- Verify solution satisfies all constraints
|
||||
|
||||
## Algorithm Patterns
|
||||
|
||||
### Mathematical Sequences
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Fibonacci:
|
||||
a = 0, b = 1;
|
||||
while (...) {
|
||||
next = a + b;
|
||||
a = b;
|
||||
b = next;
|
||||
}
|
||||
|
||||
Factorial:
|
||||
result = 1;
|
||||
for (i = 1; i <= n; i++)
|
||||
result *= i;
|
||||
|
||||
Prime checking:
|
||||
for (i = 2; i < sqrt(n); i++)
|
||||
if (n % i == 0) return 0;
|
||||
return 1;
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Iterative or recursive patterns
|
||||
- Arithmetic progressions
|
||||
- Number theory operations (modulo, divisibility)
|
||||
- Known sequence generation
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-decompilation pattern="(fibonacci|factorial|prime)"
|
||||
→ Find named functions (if not stripped)
|
||||
|
||||
get-decompilation of suspicious function
|
||||
→ Identify mathematical pattern
|
||||
|
||||
Recognize by structure:
|
||||
→ Two-variable update (Fibonacci)
|
||||
→ Multiplication accumulator (factorial)
|
||||
→ Modulo divisibility (prime check)
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Recognize the algorithm
|
||||
- Understand how it validates input
|
||||
- Derive required input or replicate logic
|
||||
|
||||
### Matrix Operations
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Matrix multiplication:
|
||||
for (i = 0; i < rows; i++)
|
||||
for (j = 0; j < cols; j++)
|
||||
for (k = 0; k < inner; k++)
|
||||
result[i][j] += a[i][k] * b[k][j];
|
||||
|
||||
Linear transformations:
|
||||
output[i] = matrix[i][0] * input[0] + matrix[i][1] * input[1] + ...;
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Triple-nested loops (matrix multiply)
|
||||
- 2D array indexing: `array[i][j]` or `array[i * width + j]`
|
||||
- Accumulator in inner loop
|
||||
- Linear combinations of input
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-decompilation pattern="\\[.*\\]\\[.*\\]"
|
||||
→ Find 2D array access
|
||||
|
||||
get-decompilation showing nested loops
|
||||
→ Count loop depth (3 = likely matrix multiply)
|
||||
|
||||
read-memory at matrix constants
|
||||
→ Extract transformation matrix
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Extract matrix
|
||||
- Invert matrix (if square and invertible)
|
||||
- Apply inverse to expected output to get required input
|
||||
|
||||
### State Machine Patterns
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Explicit state variable:
|
||||
int state = STATE_INIT;
|
||||
while (running) {
|
||||
switch (state) {
|
||||
case STATE_INIT: /* ... */ state = STATE_READY; break;
|
||||
case STATE_READY: /* ... */ state = STATE_PROCESS; break;
|
||||
case STATE_PROCESS: /* ... */ state = STATE_DONE; break;
|
||||
}
|
||||
}
|
||||
|
||||
Implicit state (position in input):
|
||||
for (i = 0; i < len; i++) {
|
||||
if (/* condition based on i and input */)
|
||||
/* different processing for different positions */
|
||||
}
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- State variable with multiple values
|
||||
- Large switch statement on state
|
||||
- State transitions (state = NEW_STATE)
|
||||
- Different behavior based on current state
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-decompilation pattern="(case|switch)"
|
||||
→ Find switch statements
|
||||
|
||||
get-decompilation of state machine
|
||||
→ Map state transitions
|
||||
|
||||
rename-variables to clarify states
|
||||
→ current_state, next_state, etc.
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Map state transition graph
|
||||
- Identify accepting states (success)
|
||||
- Determine input sequence that reaches accepting state
|
||||
|
||||
## Obfuscation Patterns
|
||||
|
||||
### Control Flow Obfuscation
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Opaque predicates (always true/false):
|
||||
if (x * x >= 0) // Always true
|
||||
real_code();
|
||||
else
|
||||
never_executed();
|
||||
|
||||
Dispatcher loops:
|
||||
while (1) {
|
||||
switch (dispatch_value) {
|
||||
case 0: /* block A */; dispatch_value = 5; break;
|
||||
case 5: /* block B */; dispatch_value = 2; break;
|
||||
case 2: /* block C */; dispatch_value = -1; break;
|
||||
case -1: return;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Unnecessary conditionals
|
||||
- Complex control flow with simple logic
|
||||
- Dispatcher-based execution (case jumps)
|
||||
- Dead code branches
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
get-decompilation of obfuscated function
|
||||
→ Look for unusual control flow
|
||||
|
||||
set-bookmark type="Warning" for suspicious patterns
|
||||
→ Mark opaque predicates, dispatchers
|
||||
|
||||
Focus on data flow, ignore control flow complexity
|
||||
→ Track input transformation regardless of jumps
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Ignore obfuscation, trace data flow
|
||||
- Use dynamic analysis to observe actual execution path
|
||||
- Simplify manually or with deobfuscation tools
|
||||
|
||||
### String Obfuscation
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Stack strings (character-by-character):
|
||||
str[0] = 'f'; str[1] = 'l'; str[2] = 'a'; str[3] = 'g';
|
||||
|
||||
Encrypted strings (decrypted at runtime):
|
||||
decrypt_string(encrypted_data, key, output);
|
||||
|
||||
Computed strings:
|
||||
for (i = 0; i < len; i++)
|
||||
str[i] = base[i] ^ key;
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Character assignments to array
|
||||
- String decryption functions
|
||||
- XOR or arithmetic on character arrays
|
||||
- Strings not visible in static string list
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
get-strings may not show obfuscated strings
|
||||
→ Use decompilation to find construction
|
||||
|
||||
search-decompilation pattern="\\[0\\] = "
|
||||
→ Find character-by-character assignments
|
||||
|
||||
find-cross-references to decryption functions
|
||||
→ Locate where strings are revealed
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Identify deobfuscation routine
|
||||
- Extract encrypted data and key
|
||||
- Decrypt manually or use dynamic analysis to observe decrypted string
|
||||
|
||||
### Anti-Debugging (CTF Context)
|
||||
|
||||
**Recognition Signature:**
|
||||
```
|
||||
Debugger detection:
|
||||
if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) exit(1); // Linux
|
||||
if (IsDebuggerPresent()) exit(1); // Windows
|
||||
|
||||
Timing checks:
|
||||
start = time();
|
||||
/* short operation */
|
||||
end = time();
|
||||
if (end - start > THRESHOLD) exit(1); // Detected breakpoint delay
|
||||
|
||||
Self-modification:
|
||||
Decrypt code section at runtime
|
||||
Execute decrypted code
|
||||
Re-encrypt afterwards
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Debugger detection APIs
|
||||
- Timing measurements
|
||||
- Memory protection changes
|
||||
- Code modification at runtime
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
get-symbols includeExternal=true
|
||||
→ Look for: ptrace, IsDebuggerPresent, time, gettimeofday
|
||||
|
||||
search-decompilation pattern="(ptrace|IsDebugger|time)"
|
||||
→ Find anti-debug checks
|
||||
|
||||
find-cross-references to VirtualProtect, mprotect
|
||||
→ Identify self-modifying code
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Patch out anti-debug checks (NOP the exit)
|
||||
- Use anti-anti-debugging tools
|
||||
- Analyze in sandbox that hides debugger
|
||||
- For CTF, often acceptable to patch binary
|
||||
|
||||
## Common CTF Tricks
|
||||
|
||||
### Flag Format Validation
|
||||
|
||||
**Pattern:**
|
||||
```
|
||||
Check prefix:
|
||||
if (strncmp(input, "flag{", 5) != 0) return 0;
|
||||
|
||||
Check suffix:
|
||||
if (input[len-1] != '}') return 0;
|
||||
|
||||
Check length:
|
||||
if (strlen(input) != EXPECTED_LEN) return 0;
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- String comparison with literal "flag{" or "CTF{"
|
||||
- Bracket/brace checks
|
||||
- Length validation
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-strings-regex pattern="(flag\\{|CTF\\{)"
|
||||
→ Find flag format strings
|
||||
|
||||
get-decompilation of validation
|
||||
→ Extract format requirements
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Note format requirements
|
||||
- Focus on solving for content between delimiters
|
||||
- Reconstruct full flag with proper format
|
||||
|
||||
### Multi-Stage Validation
|
||||
|
||||
**Pattern:**
|
||||
```
|
||||
Stage 1: Check format (flag{...})
|
||||
Stage 2: Check length (must be 32 characters)
|
||||
Stage 3: Check checksum (sum must equal X)
|
||||
Stage 4: Check encryption (encrypted content matches Y)
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Multiple validation functions called in sequence
|
||||
- Early exits on failure
|
||||
- Progressive constraints
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
find-cross-references to validation function
|
||||
→ See if called from multi-stage validator
|
||||
|
||||
get-decompilation of main validator
|
||||
→ Identify call sequence
|
||||
|
||||
Analyze each stage separately
|
||||
→ Understand cumulative constraints
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Solve each stage's constraints
|
||||
- Combine solutions (flag must satisfy ALL stages)
|
||||
- Work backwards from most constrained to least
|
||||
|
||||
### Hidden Success Path
|
||||
|
||||
**Pattern:**
|
||||
```
|
||||
Obvious failure message:
|
||||
printf("Wrong!\n");
|
||||
|
||||
Hidden success logic:
|
||||
if (/* complex condition */)
|
||||
system("cat /flag.txt"); // No message, just action
|
||||
```
|
||||
|
||||
**What to look for:**
|
||||
- Success action without visible message
|
||||
- File access (cat flag, open flag.txt)
|
||||
- Network communication of flag
|
||||
- Success indicated by lack of "Wrong" message
|
||||
|
||||
**ReVa detection:**
|
||||
```
|
||||
search-strings-regex pattern="(flag|/flag|flag\\.txt)"
|
||||
→ Find flag file references
|
||||
|
||||
find-cross-references to flag file
|
||||
→ Locate success path
|
||||
|
||||
get-decompilation of success condition
|
||||
→ Understand requirements
|
||||
```
|
||||
|
||||
**Solution approach:**
|
||||
- Don't rely on "Correct!" message
|
||||
- Look for flag output actions
|
||||
- Check for file reads, network sends
|
||||
- Success may be silent
|
||||
|
||||
## Using These Patterns
|
||||
|
||||
### Pattern Matching Workflow
|
||||
|
||||
1. **Observe code structure**
|
||||
- Loops, conditionals, function calls
|
||||
- Data types, array sizes
|
||||
- Constants and literals
|
||||
|
||||
2. **Compare to pattern catalog**
|
||||
- Does this match a crypto pattern?
|
||||
- Is this an encoding scheme?
|
||||
- Looks like input validation?
|
||||
|
||||
3. **Verify with specific checks**
|
||||
```
|
||||
Hypothesis: This is AES
|
||||
Check 1: read-memory at constant array → Matches AES S-box? ✓
|
||||
Check 2: Count loop iterations → 10, 12, or 14? ✓
|
||||
Check 3: Block size 16 bytes? ✓
|
||||
Conclusion: AES confirmed
|
||||
```
|
||||
|
||||
4. **Apply pattern-specific solution**
|
||||
- AES → Extract key, decrypt
|
||||
- XOR → Extract key, XOR again
|
||||
- Constraint validation → Extract constraints, solve
|
||||
|
||||
### Quick Reference Decision Tree
|
||||
|
||||
```
|
||||
Does it have loops with XOR?
|
||||
→ Check Simple XOR Patterns
|
||||
|
||||
Does it have large constant arrays?
|
||||
→ Check Block Cipher or Hash Patterns
|
||||
|
||||
Does it have swap operations and modulo?
|
||||
→ Check Stream Cipher Patterns
|
||||
|
||||
Does it have character-by-character comparison?
|
||||
→ Check Input Validation Patterns
|
||||
|
||||
Does it have 64-character lookup table?
|
||||
→ Check Base64 Pattern
|
||||
|
||||
Does it have mathematical operations (factorial, fibonacci)?
|
||||
→ Check Algorithm Patterns
|
||||
|
||||
Is control flow overly complex?
|
||||
→ Check Obfuscation Patterns
|
||||
```
|
||||
|
||||
### Combining Patterns
|
||||
|
||||
Real challenges often combine multiple patterns:
|
||||
|
||||
**Example: Crypto + Validation**
|
||||
```
|
||||
Input → Format Check (flag{...}) → XOR Decode → AES Decrypt → Compare to Expected
|
||||
```
|
||||
|
||||
**Solve:**
|
||||
1. Extract format requirements
|
||||
2. Identify XOR key
|
||||
3. Identify AES key
|
||||
4. Extract expected value
|
||||
5. Work backwards: AES_decrypt(XOR_decode(expected)) with known keys
|
||||
|
||||
**Example: Encoding + Constraint**
|
||||
```
|
||||
Input → Base64 Decode → Constraint Check (sum == X, product == Y)
|
||||
```
|
||||
|
||||
**Solve:**
|
||||
1. Extract constraints on decoded values
|
||||
2. Solve constraints
|
||||
3. Base64 encode solution
|
||||
|
||||
## Remember
|
||||
|
||||
Patterns are **recognition shortcuts**, not rigid rules:
|
||||
- Use patterns to quickly identify challenge type
|
||||
- Adapt pattern solutions to specific implementation
|
||||
- If pattern doesn't fit, analyze from first principles
|
||||
- Document your pattern matches with bookmarks/comments
|
||||
- Build your own pattern library from experience
|
||||
|
||||
When you recognize a pattern, you skip hours of analysis and jump directly to solution strategy.
|
||||
Reference in New Issue
Block a user