If your just joining us, this is the second part of me trying to solve the Protostar exploit exercises. You can read the Previous post if you want to.
I have been struggling with this level for quite some time. Every time I think I got it right, the memory-corruption gods smack me back down to earth. Previously I’ve been solving the protostar stack-challenges without a complete understanding of how things were happening.
Since then I’ve read this book, and recently really just sat down allowed myself not to rush through this challenge.
By writing this post - I mostly taught myself what’s going on.
Pro-tip: putting things on the stack moves down in memory, taking things off moves up in memory.
Stack5 is a standard buffer overflow, this time introducing shellcode.
This level is at /opt/protostar/bin/stack5
- At this point in time, it might be easier to use someone elses shellcode
- If debugging the shellcode, use \xcc (int3) to stop the program executing and return to the debugger
- remove the int3s once your shellcode is done.
Let’s have a look at the code.
Listing 1-0: Excerpt from stack5.c
Let’s have a look in gdb.
$ gdb -q stack5 (gdb) set disassembly-flavor intel (gdb) disassemble
Listing 1-1: Starting gdb
Listing 1-2: Disassembly of main from stack5
I made the following simplification of what’s going on after the alignment of esp & before the call to gets. Let’s assume for simplicity that esp is initially 100.
esp is decremented by 80 (hex 50) to make room for the array.
20 | | <- esp 21 | | ... 99 | | 100 | | # esp was pointing here before :)
esp is adjusted by incrementing it by 16 (-80+16= -64), and it’s saved in the eax register.
20 | | <- esp 21 | | ... 35 | | 36 | | <- eax
Save the pointer on the stack
19 | | 20 | 36 | <- esp 21 | |
Here’s a couple of screenshots, illustrating in gdb what’s going on with the actual memory that holds the input.
Note that a array of 64
As in C still has a length of 65, since the
array is terminated by null.
Figure 1-0: Feeding the program 63 As
Figure 1-1: Feeding the program 64 As
Figure 1-2: Feeding the program 65 As
As you can see, our array is slowly eating away at the data on the
stack, in our case
Those pieces of bits are popped of the stack in the
instruction. The following
ret instruction basically pops the top of the stack
into eip & execution proceeds at the new location pointed at by eip.
We can find out what part of the stack we need to overwrite by
examining the top of the stack just before executing the
Figure 1-3: Examining the top of the stack before executing
How many bytes do we need to feed the program to overwrite that piece of memory?
We just subtract our goal with the address of our array & get how many bytes we need to feed.
0xbffff7c0 - 0xbffff770 = 0x50 (decimal 80)
A array of 80 characters would completely overwrite the address popped by ret, Right?
Figure 1-4: Overwriting the instruction pointer by feeding the program 80
Let’s place some instructions in the buffer, along with some garbage, ending with the address which points to our buffer. I used some python to generate the payload.
When fed into the program, our shellcode executes - It does absolutely nothing. But it’s there, executing :)
So we’re close, but we still need to figure out some shellcode that we would want to use.
This, hopefully is the easy part. We just go to google, type shellcode & press enter.
I stumbled upon this over at exploit-db.
Since the shellcode’s length is larger than our 4 instructions, we adjust the amount of
we’re feeding & it should work just fine.
Thanks for reading.