Use-After-Free Vulnerability (UAF) and Demo with Protostar Heap 2

Introduction:

Basically, UAF happens when the program tries to access a portion of memory after it has been freed that may force the program to crash and based on the flow of the program you might get arbitrary code execution.

The bug mostly affects C++ code with an issue called in programming “dangling pointer” and it has been the most relevant bug in browsers exploitation due to its simplicity in exploitation but it is hard to discover.

Steps to exploit UAF vulnerabilities:

  • Prepare the heap (Often by heap spraying)
  • Try to delete the object (which will be called later)
  • Replace the deleted object with your malicious fake object which has the same size
  • Trigger the vulnerability

Demo:

First, download Protostar ISO and setup it on Virtualbox or VMware

Download Protostar : https://github.com/ExploitEducation/Protostar/releases/download/v2.0.0/exploit-exercises-protostar-2.iso

Description

This level examines what can happen when heap pointers are stale.

This level is completed when you see the “you have logged in already!” message

This level is at /opt/protostar/bin/heap2

Source Code

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

struct auth {
  char name[32];
  int auth;
};

struct auth *auth;
char *service;

int main(int argc, char **argv)
{
  char line[128];

  while(1) {
    printf("[ auth = %p, service = %p ]\n", auth, service);

    if(fgets(line, sizeof(line), stdin) == NULL) break;
    
    if(strncmp(line, "auth ", 5) == 0) {
      auth = malloc(sizeof(auth));
      memset(auth, 0, sizeof(auth));
      if(strlen(line + 5) < 31) {
        strcpy(auth->name, line + 5);
      }
    }
    if(strncmp(line, "reset", 5) == 0) {
      free(auth);
    }
    if(strncmp(line, "service", 6) == 0) {
      service = strdup(line + 7);
    }
    if(strncmp(line, "login", 5) == 0) {
      if(auth->auth) {
        printf("you have logged in already!\n");
      } else {
        printf("please enter your password\n");
      }
    }
  }
}

In this demo, I didn’t use the protostar machine but instead, I used the source code provided and compiled it to generate the vulnerable program.

gcc source_code.c -o heap2

Let’s take the source code apart and understand every function

First there is a struct called “auth” and it has two variables

  • name (array of chars)
  • auth (integer number)
 struct auth {
  char name[32];
  int auth;
};

After that we declare two global variables and one local variable in the main function

  • struct auth *auth;
  • char *service;
  • char line[128]; (local variable)

The whole logic of the program resides in the while loop that prints the values of what “auth” and “service” variables point to, then it takes the user input and checks it for 4 cases:

1- if the user input is “auth”, it allocates memory for it with malloc() function and it takes the rest of the input as the name variable of the struct auth.

if(strncmp(line, "auth ", 5) == 0) {
      auth = malloc(sizeof(auth));
      memset(auth, 0, sizeof(auth));
      if(strlen(line + 5) < 31) {
        strcpy(auth->name, line + 5);
      }
    }

2- if the user input is “reset” it frees the auth object (which will cause the UAF vulnerability later on)

if(strncmp(line, "reset", 5) == 0) {
      free(auth);
    }

3- if the user input is “service”, it takes the rest of the input and allocates memory for it with strdup() function which returns a pointer to the string and allocates memory for it with malloc() function and can be freed with free() function.

if(strncmp(line, "service", 6) == 0) {
      service = strdup(line + 7);
    }
    

4- if the user input is “login”, it makes another check whether the integer auth of the struct auth has a value greater than zero or not and print different messages based on that.

if(strncmp(line, "login", 5) == 0) {
      if(auth->auth) {
        printf("you have logged in already!\n");
      } else {
        printf("please enter your password\n");
      }

Based on the explanation of the source code our goal is to get the message “you have logged in already!\n” and we can achieve that if the integer auth has a value greater than zero but wait the integer auth never set during the program flow.

Let’s run the program and play around

Now if we used the service function to define a service we will notice that the service points to the same value as auth because the heap allocation will start from the beginning and doesn’t care if this position in memory has a previous value or not because we freed it.

if we define a new service but with a greater length of the size of the struct auth we can overwrite the integer auth in the struct and make it contain a value greater than zero.

And you got it!, that was a classic UAF vulnerability wait for more advanced ones in next tutorials.

Leave a Reply