Stack7 Exploit-Excercises | ROP exploit

Stack7 is the final challenge that Exploit Exercises offers to get to understand and exploit the stack, and it's made purposefully so you understand how ROP ( return oriented programming ) works and write the correspondent exploit.

Honestly, this level taught me more than just how ROP works. It made me realize that I wasn't learning binary hacking the proper way. Up to a few days ago, I tried to learn binary hacking the same way you learn web hacking: you understand the concept because you can ( most of the time ) see it.
That isn't what happens with binary. In the reversing and exploiting world, there are levels of abstraction, so what you think is happening, might not be happening for the reason you thought it did, but you can't see it, so you don't know and end up having the wrong idea.

In this level, I learned that, the more you know about binary hacking, the more you'll understand the first basic white papers you read and thought you understood ( but you didn't ).
So it's totally okay and necessary to re-read old stuff, there's always hidden gems :)

About ROP

Return Oriented Programming is, from the documents in ExploitDB about ROP, a set of small instruction sequences available in either the binary or libraries linked to the application, which receive the name of gadgets.
Does that definition help? Well, if you've never heard about ROP before this challenge, then it probably doesn't.
Let's get a little bit back.

Remember how the code of a program looks like in assembly? In the stack5 post I presented a small example of a hello world program.

push rbp
mov rbp,rsp
lea rdi,[rip+0x9f] # 0x6f4
mov eax,0x0
call 0x530 <printf@plt>
mov eax,0x0
pop rbp
ret

Take a look at the last two instructions.
Also note that RBP is the base pointer, and its predecessor is EBP on x86 architecture.

pop rbp
ret

We could all agree that return instructions happen quite often in a program, and the instructions that preceed them, usually pop, are also a very common occurrence, aren't they?

Now, the name this return ending instruction sequences receive is gadgets.

Why do gadgets matter?

Now we know what a gadget is, we may ask ourselves why would they be important for us.

There is a way to protect memory regions from having external code executed inside them, this technique is commonly known as DEP ( data execution prevention ). It can be also known as WorX ( write or execute ), stating that these memory regions can either be writable or executable, but never both.

Somewhere in the past, 2007, someone presented the first papers that introduced ROP to the world, and then exposed it to the world in the Black Hat con in 2008. This someone is known as Hovav Shacham. 
I added a picture from the blog of Zynamics

From the papers we deduce that we can bypass DEP with ROP, but how? How can one thing lead to another?
I think this is a great chance for me to begin introducing and explaining Stack7 :D

The code

The code was veeeeery similar to how stack6 code looked like.



I'm going to point out some things which i didn't point out in stack5.

First of all, __builtin_return_address(0). That function will be the return address from the current function, and that value will be assigned to ret. So now, ret holds the return address from getpath().

The second thing is the ret & 0xb0000000 part. That is a process you may know as anding.

In anding, if two values compared are both 1, the result is 1. If two values compared are both 0, the result is 0. And if one value is 0 and the other is 1, the result will be 0.
So in this case, if the two values are b, the result will be b. Otherwise it will be 0.
That means that if the return address from the current function starts with b, the program will bzzzt us! Evil program.

Further into the exploit, we'll discover why is it bzzzing us if the return address starts with b.

Falling down the stack and failing at exploiting

First of all, to check my theory that addresses starting with 0xb got bzzzed, I overflowed the buffer and then redirected program execution to libc, where /bin/sh is found and addresses start with 0xb.

The wrong exploit:

$ python -c 'print "A"*80 + "\xbf\x63\xfb\xb7"' > exploit


As you can see, it does indeed bzzt us.

If you read the PDF from ExploitDB about ROPs, you'd say that, hey, why don't we find a gadget which we can use to return to an address we control?
Because the check is only happening at the first ret, right? It is only checking for the current function, so the addresses we jump to from there will not be checked.

At this point I tried many many things, so many that I had time to become head of the mafia, build my own empire, see its rise and fall and then got back to what I was previously doing: this exploit.
What I tried: assign the exploit to an environment variable and look into libc.
It didn't work and I was going insane.

Then, a friend Pyhscript told me, hey, what about reusing old code? So I reached for my old friend the NOP sled.

With the NOP sled, this is how the exploit would look like:
  • Padding: the limit was 80, then if overflowed the buffer.
  • Return: we selected a gadget by inspecting the binary, I'll explain now.
  • Second return: the second address to return to, I will explain how and why I chose the one I chose.
  • NOP sled: 90 bytes of sliding fun.
  • Shellcode to root.
First and second return addresses

To find the first return address, I only needed to find out where in the binary there were gadgets.

$ objdump -D stack7 | grep ret

I picked a random address from the returned list and used that one for my exploit.

Now, for the second address. I know this one was used in the stack5 post too, but I didn't realize at the moment that I hadn't explained why I chose that one, so let me explain myself.

Once we hit the first return, we'd want to go somewhere where we can add the NOP slide and shellcode afterwards. Why not going to where the stack pointer points? The second return address is, effectively, the address of the stack pointer after we ran the binary and before it could finish.

Who am I?

To gain control I added together what I explained before and... access granted! :)



Did you see how many times it did not work? And that's just because the terminal window was that big, because the fail train goes uuuuuup...

Comments

Popular Posts