Note: This post summarizes the techniques discussed in Corelan post on jumping to shellcode. Read it for better understanding.
So you managed to control EIP and you want to jump to your shellcode. Check the condition for each technique and see if you can make it work to reach your shellcode.
1. JMP/CALL register
Conditions:
- A register points to shellcode.
Example:
[Register]→[Shellcode]EIP→JMP/CALL [register]EIPnow points to[register]where shellcode.
Pros:
- Easy to apply.
- Common instruction.
Cons:
- None.
2. POP RET / POP POP RET / POP POP POP RET
Condition:
- Address at
[ESP+4],[ESP+8],[ESP+12](and so on) points to address to shellcode OR directly to shellcode.
Example 1:
[ESP]→[4 bytes][Address to shellcode].EIP→POP [register]followed byRET.POP [register]:ESPnow points toold_ESP + 4RET:EIPnow contains address to shellcode.
EIPnow points to shellcode.
Example 2:
[ESP]→[8 bytes][Address to JMP ESP][shellcode].EIP→POP [register]followed byPOP [register]followed byRET:POP [register],POP [register]will get rid of 8 bytes,new ESP→old ESP + 8(Address toJMP ESP)RETplaces address toJMP ESPinEIPand nowESPnow points to shellcode.JMP ESP:EIPnow containsESP
EIPpoints to current ESP value which points to start of shellcode.
Pros:
- Straightforward (slightly harder than method 1).
- Lots of possible combinations to find instruction.
Cons:
- Less frequent pattern.
3. PUSH RET
Condition:
- A register points to shellcode and can’t/don’t want to use method 1.
Example:
[Register]→[Shellcode]EIP→ PUSH [register], followed byRET- Stack will first push register, then pop it to
EIP.
- Stack will first push register, then pop it to
EIPnow points to shellcode.
Pros:
- Easy to apply.
- Fallback if method 1 can’t be done.
Cons:
○ None.
4. JMP [register + offset]
Condition:
- A register + offset points to shellcode.
Example:
[Register]→[Shellcode]EIP→JMP [register + offset]EIPwill point to[register + offset]where the shellcode starts.
Pros:
- Easy to apply.
Cons:
- Doesn’t work if
[register + offset]points to address to shellcode asESPdoesn’t change and aRETwon’t work.
5. Blind return
Condition:
- Shellcode is always loaded to the same address.
- Address doesn’t contain a null byte.
- You control at least the first 4 bytes at
[ESP]
Example:
- Shellcode is always at
0xdeadbeef - Since you control the first 4 bytes at
ESP, put0xdeadbeefatESP. - By pointing
EIPto aRET, address atESPwill be popped toEIP. EIPnow points to address0xdeadbeefwhere the shellcode starts.
Pros:
- Easiest method, only need a RET.
- Fixed address.
Cons:
- Heavy dependency on hardcoded address.
- Address can’t contain null byte (good luck with stack at low address).
- Assumes no ASLR and/or DEP.
6. POPAD
Condition:
- Shellcode is located at
[ESP + 32x + offset] - Enough controllable space to execute
POPADy times thenJMP ESP.
Example:
[ESP + 240]→[Shellcode][ESP + 32 * 7]→[NOP sled][ESP] → POPAD 7 times followed byJMP ESP`EIP→[JMP ESP]EIPwill executePOPAD7 times,ESP=old_ESP+ 224EIPgoes overNOP sledEIPafter executingNOP sled, it will point to[ESP + 240]where the shellcode starts.
Pros:
POPADis a single byte.ESPgets incremented with 32 every time POPAD is executed.
Cons:
- Requires NOP sled.
- Less reliable than Method 1/2/3/4
7. Short jumps (backwards, forwards, conditional)
Condition:
- Shellcode is located at
[ESP + offset]where -128 < offset < 127.
Example:_
[ESP + 30]→[Shellcode][ESP]→JMP 30EIP→[JMPESP]EIPwill execute a short JMP
EIPwill point to[ESP + 30]where the shellcode starts.
Pros:
- Simple instruction.
- Reliable, no NOP sled is needed.
Cons:
- Restricted by being a short JMP.
8. Hardcoded address
Condition:
- Shellcode is always located at specific address.
Example:
0xdeadbeef→[shellcode]EIP→JMP ESPESP→JMP 0xdeadbeef
Pros:
- Simple instruction.
Cons:
- Unreliable.
- Address can’t contain null bytes.
Following repo contains some snippets on various payload generation for the techniques below: https://github.com/abatchy17/ExploitDevSnippets/tree/master/Corelan
- Abatchy