Cheatsheet
Find padding until BOF
BOF in terminal + dmesg
- Generate a cyclic sequence (take around x2 buffer size)
pwn cyclic 40
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaa
- Run the vulnerable binary, and segfault with your sequence
./vuln
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaa
zsh: segmentation fault ./main
- Check dmesg for the segfault EIP
dmesg -t
# ...
main[116941]: segfault at 61616169 ip 0000000061616169 sp 00000000ffffd2e0 error 14 in libc.so.6[f7c00000+22000]
Code: Unable to access opcode bytes at RIP 0x6161613f.
- Calculate padding using pwntools
pwn cyclic -l 0x61616169
32
Calculate addresses in GDB
You can use GDB to calculate the distance between the address of the buffer, and the address of the stored EIP.
- Run your vulnerable binary in GDB
gdb main
- Put a breakpoint on the function that takes user input
pwndbg> b *pwnme + 78
- Run until breakpoint
pwndbg> r
- Check the address that stores the return address, and the address of your buffer
pwndbg> stack 20
00:0000│ esp 0xffffd1f0 —▸ 0xffffd20c ◂— 0x0
01:0004│ 0xffffd1f4 ◂— 0x0
02:0008│ 0xffffd1f8 —▸ 0xf7c1ca2f ◂— '_dl_audit_preinit'
03:000c│ 0xffffd1fc —▸ 0x80491bd (pwnme+12) ◂— add ebx, 0x2e37
04:0010│ 0xffffd200 —▸ 0xf7fc14a0 —▸ 0xf7c00000 ◂— 0x464c457f
05:0014│ 0xffffd204 —▸ 0xf7fd98cb (_dl_fixup+235) ◂— mov edi, eax
06:0018│ 0xffffd208 —▸ 0xf7c1ca2f ◂— '_dl_audit_preinit'
07:001c│ eax 0xffffd20c ◂— 0x0
... ↓ 4 skipped
0c:0030│ 0xffffd220 ◂— 0x1
0d:0034│ 0xffffd224 —▸ 0xf7e1cff4 (_GLOBAL_OFFSET_TABLE_) ◂— 0x21cd8c
0e:0038│ ebp 0xffffd228 —▸ 0xffffd238 ◂— 0x0
0f:003c│ 0xffffd22c —▸ 0x8049238 (main+21) ◂— mov eax, 0
esppoints to the address of the buffer.eaxis the bufferstored eipis belowebp.
- Calculate distance between both
pwndbg> print 0xffffd22c-0xffffd20c
$1 = 32
So there is 32 bytes between the buffer's address, and the saved EIP.
Automate using pwntools
You can automate this process, directly in your python exploit.
find.py
from pwn import *
target = './main'
def find_offset() -> int:
p = process(target)
p.sendline(cyclic(40)) # just like pwn cyclic 40
p.wait() # wait for process to generate coredump
core = Coredump('./core') # load the core dump
offset = cyclic_find(core.fault_addr) # load the segfault address
return offset
print(find_offset())
Executing the script should print:
└─$ python3 find.py
[+] Starting local process './main': pid 125926
[*] Process './main' stopped with exit code -11 (SIGSEGV) (pid 125926)
[+] Parsing corefile...: Done
[*] '/home/vagrant/course/examples/ret2win/ret2win_guided/core'
Arch: i386-32-little
EIP: 0x61616169
ESP: 0xffffd2e0
Exe: '/home/vagrant/course/examples/ret2win/ret2win_guided/main' (0x8048000)
Fault: 0x61616169
32
troubleshooting
If you are not using the provided docker image, and it does not work (cannot find Corefile) even if it segfaulted,
you may need to set your core_pattern.
echo core | sudo tee /proc/sys/kernel/core_pattern
Execute a process with other arguments
If you want to run ./main %p.%p.%p inside your python exploit :
from pwn import *
target = './main'
elf = context.binary = ELF(target)
myargs = ["%p.%p.%p"]
p = elf.process(argv=myargs)