So today, we are going to look at the second challenge of ROP Emporium and that’s split. We are going to look at X86 and X86_64 version of the binary, reverse engineer it, analyzing the stack frame and finally capturing the flag. Let’s get into it.
Before Diving into this challenge, I would like to suggest to go through some basics of ROPgadgets. The GitHub descriptions says “This tool lets you search your gadgets on your binaries to facilitate your ROP exploitation. ROPgadgets supports ELF/PE/Mach-O/Raw formats on x86, x64, ARM, ARM64, PowerPC, SPARC, MIPS, RISC-V 64, and RISC-V Compressed architectures.” Make sure you familiar yourself with the ROPgadgets tool. It’s really very simple.
x86 Architecture
Attack Planning:
We have a two strings present in our binary. “/bin/ls” and “/bin/cat flag.txt”. But the system function executes “/bin/ls”. NX Enabled which means we can’t insert any malicious payload instead of “/bin/ls”. If you’re following the previous blog than the same exploit will work but does not print the flag instead it executes the “/bin/ls” command. Which means we need to replace the “/bin/ls” of the system function argument with “/bin/cat flag.txt” so that we can grab the flag.
Looking at the image above, we can see that the NX enabled which means it will prevent us adding payloads onto the stack and any runtime stack execution is disabled. Now let’s get into gdb and list the functions attached to this binary.
Looking at the function list above, we have one interesting function (I did disassemble almost all the function before making this call) and that is ‘usefulFunction‘.
Disassembling the usefulFunction shows that there’s a system function. You can disassemble the pwnme and main function and notice you won’t see the system function in it. Anyways that’s fine. Printing the string form of what’s holding at the “0x08048615 <+9>: push 0x804870e” right before calling the system@plt function tells me that it stores “/bin/ls” string.
Perfect. We will need to replace this with “/bin/cat flag.txt” in our final exploit. We’ll look into that later.
Finding the OffSet
So for calculating the OffSet, I was initially used gef as well as peda but I was getting different offset values for the same binary hence I switch to pattern_offset command on Kali. Here’s how I calculate the offset for x86 Binary.
If you are using gef or peda within GDB while following this article, you can always disabled loading your plugin by commenting out the gdb plugin in /home/ringbuffer/.gdbinit file.
Creating the pattern of 100 byets
Running the program with the give pattern.
Printing the registers in gdb using info register command.
Notice the eip (Next Instruction) register holds the value 0x35624134. Now lets find out the offset based on the value we have seen here in EIP register.
So we have our offset 44. Let’s form up one liner to get the flag. We notice above that the ‘0x804870e‘ is pushed right before it call the system function when we disassemble the ‘usefulFunction’ and it is the string ‘/bin/ls’ command. We will need to first find the address of the “/bin/cat” command. To do this, I simply put the break point on ret in the main function and run the program with gdb-peda. Then entering the ‘find’ command retunes me the address of the “/bin/cat” command.
Cool! we have our memory location for the string “/bin/cat flag.txt”. The one liner exploit is really simple as follow:
The one liner simply adds b”A”*44 following to the address of the system function and address of the string “/bin/cat”. Great! We have got our flag. Now we can form up a working exploit as follows:
┌──(ringbuffer㉿kali)-[~/Downloads/BufferOverFlow/split32]
└─$ more exploit.py
from pwn import *
p = process('./split32')
payload = b"A"*44 + p32(0x0804861a) + p32(0x804a030)
p.send(payload)
p.interactive()
If you notice, for x86 Architecture, we do not use ROPgadgets and the reason is that the binary allowed us to alter the string at the given address by replacing “/bin/ls” with “/bin/cat” However, that is not the case with X86_64 Architecture.
x86_64 Architecture
OffSet Calculation
Again, I’m using the same pattern_offset method to calculate the offset but for this binary, we are going to take the address of the RBP (Base Pointer) register instead of the RIP registers because the RIP register points to the pwnme function. Here’s my offset calculation.
So we have our offset 32 plus 8 bytes for padding which makes it 40;
Time to play with ROPgadgets
The plan here is to find “pop” instructions within binary and when program encounter the payload, it jump controls to the pop instructions which then points to the memory address of “/bin/cat flag.txt” following to that jump back to the execution of the system function inside the ‘usefulFunction’ method.
So we have the memory address of our ‘pop rdi’ instruction in the memory. The structure of our exploit is as follows:
40 bytes of A + address of pop rdi instruction + address of the string “/bin/cat” instruction + address of the “system” function
Bingo! so our one liner goes into the file called payload1 and then running the binary importing the payload returns the flag right after the “Thank you!” word.
We can form an exploit as follows:
from pwn import *
context.bits = 64
p = process('./split')
system_addr = 0x000000000040074b
bincat_addr = 0x601060
poprdi_addr = 0x00000000004007c3
payload = b"A"*40 + p64(poprdi_addr) + p64(bincat_addr) + p64(system_addr)
p.send(payload)
p.interactive()
We have got our flag.
@ringbuffer
Some of the latest posts