Protostar Stack Exploits (Solutions 6-7)
Buffer overflow exploit exercises, part three.
Protostar is a series of exercises from Exploit Exercises. In addition to three final levels, it has four basic sections: network programming, format strings, heap overflows, and stack overflows.
This series of posts contains solutions and walkthroughs for the stack overflow levels (“Stack”). It assumes basic knowledge of systems programming and is meant to serve as a reference for those stuck on certain levels. This is the final post for Stack.
Description (full): Execute shellcode with a restriction on the return address. This mimics a nonexecutable stack by barring any return addresses of the form
We’ll add one more script to our utility belt. This will help us quickly make guesses for buffer overflows.
First, we need to find the proper offset for overwriting the return address. The command below reveals that the return address is 16 bytes after the end of the 64 byte buffer, meaning that 80 bytes are needed before overwriting the return address.
For our solution, we’ll be performing a ret2libc attack. This paper by InVoLuNTaRy offers an in-depth description of the tactic (sidenote: it’s one of the most well-written papers that I’ve ever read and well worth the read). The rest of this section assumes that this paper has been read.
First, we find the addresses of the
exit() libc functions.
exit() isn’t strictly necessary, but since ret2libc ultimately calls two functions, we prefer to return without a segmentation fault.
We see that our functions have the following addresses:
Given the particular stack layout for a ret2libc attack (described in the InVoLuNTaRy paper), our solution will be of the form:
First, let’s make sure that we can actually execute code.
Working netcat solution
There are two obstacles to a working solution.
- Environmental variables with spaces don’t work. All of the following would fail:
system()will drop our root privileges (man system)
Instead, we can wrap our call to netcat in another C program, naming an executable without spaces and restoring our privileges.
system() doesn’t seem to be using the contents of our environmental variable. If we look at the environmental variables, though, we see that we were close enough:
RUN is the next variable. We then adjust our estimate for the address of
RUN by 20 bytes.
Finally, through a remote machine:
Stack: Level 7
Description (full): Execute shellcode with further restrictions on the return address. Any address of the form
0xbxxxxxxx raises an error.
The return value of a function is usually stored in the
eax register. The key to this level is the call to
return strdup(buf): this means we can find the buffer (e.g. our shellcode) in the
eax register when
The code restricts us from returning to any code on the bottom of the stack (
0xbxxxxxxx) and advises us to return to the
.text section. In particular, we’ll want to return to a
call eax instruction, which will then call our shellcode.
If we play with the numbers like in earlier levels, we’ll find that 80 bytes are needed before the return address. Our buffer overflow will look like this:
In earlier levels, we found that opening a shell with
gets(). However, we can still use it to validate our strategy:
If we give it a shot with our
nc shellcode, we’ll find the following error:
bin/sh: forward host lookup failed: Unknown host. This occurs as a complication from having options passed into the
We can add another wrapper to the
netcat.c used in Level 6 by writing our own shellcode. This shellcode will simply execute
/tmp/nc, an alias for a compiled
netcat.c. This file, in turn, calls netcat and listens via port 8080.
On a remote machine: