Challenge Info
Use ROP (Return-Oriented Programming) to call system("/bin/cat flag.txt") by chaining gadgets together.
Recon
1 | $ file split |
1 | pwndbg> checksec |
Same protections as ret2win - no canary, no PIE, but NX is enabled so we need ROP instead of shellcode.
Gathering Intel
First, let’s see what useful strings exist:
1 | $ strings split | grep "flag" |
The command we need is in the binary. Now let’s find available functions:
1 | pwndbg> info functions |
system@plt is available, and there’s a usefulFunction:
1 | pwndbg> disass usefulFunction |
This calls system() but with the wrong argument:
1 | pwndbg> x/s 0x40084a |
Not useful - we need /bin/cat flag.txt. Let’s find its address:
1 | $ objdump -s split | grep "cat flag" |
String address: 0x601060
The ROP Strategy
In x86-64, the first function argument goes in the rdi register. We need to:
- Load
0x601060(our string) intordi - Call
system()
We need a pop rdi; ret gadget:
1 | $ ROPgadget --binary split --only "pop|ret" |
0x4007c3 - exactly what we need.
Vulnerability
Same pattern as ret2win, pwnme allocates 32 bytes but reads 96 bytes (0x60):
1 | 0x00000000004006ec <+4>: sub rsp,0x20 ; 32 bytes allocated |
Offset to return address: 40 bytes (32 buffer + 8 saved RBP)
Building the ROP Chain
1 | Stack after overflow: |
Flow:
retpops0x4007c3into RIPpop rdipops0x601060into RDIretpops0x40074binto RIPsystem("/bin/cat flag.txt")executes
Exploitation
1 | from pwn import * |
Note: We use 0x40074b (the call system inside usefulFunction) rather than system@plt directly to avoid stack alignment issues that can occur with modern libc.
Key Takeaways
- ROP chains let us execute arbitrary code even with NX enabled
- x64 calling convention: first arg in
rdi, second inrsi, etc. - Gadget hunting: tools like ROPgadget find useful instruction sequences
- Stack alignment: sometimes you need to be careful about 16-byte alignment when calling libc functions