PicoCTF 2014 Write-ups

ROP 1 - 100 (Binary Exploitation)

Writeup by Oksisane

Created: 2014-11-13 21:45:39

Last modified: 2014-11-17 20:58:07

Problem

This binary is running on a machine with ASLR! Can you bypass it? The binary can be found at /home/rop1/ on the shell server. The source can be found here.

Hint

ASLR is hard to beat if you need to predict an address, but what if you don't? What does %eax contain when vuln returns? Is there any code in the program which calls or jumps to it?

Answer

Overview

Implement use ROP techniques to write and execute you'r own shellcode while defeating aslr.

Details

Before we begin, I am going to assume you know the basics of shellcode, buffer overflow attacks, and disassembling. If not, please read Overflow 1/2 before attempting this problem.

Let's begin. The hint tells us that figuring out what eax points to when the program returns is a good start, so let's do that. Opening the binary in IDA (provided here for your convenience) and breakpointing at the ret call shows us that %eax points to the start of our input buffer when vuln returns. This means that if we use our traditional buffer overflow to change the value of %eip to the value in %eax, the code will jump to the start of our buffer and start executing it as if the buffer was any other function. Since we do this without ever using any hardcoded addresses, it solves the problem of ASLR!

The first thing we need to know to exploit this is how many places up the stack we must write to change %eip. This turns out to be 76, which is common for buffer sizes of 64 such as in this problem. Next, we need to figure out how to set the value of %eip to %eax. To do this we use a ROP gadget. A ROP gadget is a snippet of code somewhere in the assembly of this program (we don't really care where since we can overwrite %eip with anything) that we can employ, out of context of whatever function it is in, to serve a purpose. In this case, we are simply looking for the ROP Gadget: call %eax. This will jump to the value stored in %eax (the start of our buffer) and then execute each line of our buffer until an error is thrown. To find the ROP Gadget we can use grep, such as shown here:

objdump -d rop1 | grep "call.*eax"

Which returns many results. Let's pick the first one, 0x08048d86 and overwrite %eip with it. Our exploit string is now:

python -c 'print ""A"*76 + "\x86\x8d\x04\x08" '

Now the program will jump to the start of our program and start executing the 0x41 (A) values as instructions until it reaches an error. The final step of this problem is adding shellcode to the start of our buffer so the program executes it instead of 0x41. Let's add this shellcode

\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80

and subtract the corresponding number of bytes from the A values we are printing to ensure we still overwrite %eip correctly. The final exploit string should look like this. Now, we print the shellcode first and then only 55 As (the shellcode is 21 bytes):

python -c 'print "\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" + "A"*55 + "\x86\x8d\x04\x08" '

which gives us our flag!

Flag

theres_no_need_to_guess