#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");
}
}
}
}
Intro
This level was a bit messy. Messy in a way that it’s poorly written, either on purpose or in a hurry, which resulted in a lot of WTF-s in the process of understanding what was going on. The level itself is not hard at all, it introduces a new type of vulnerability: use-after-free. This vulnerability is created when referencing memory after it has been freed, resulting in a crash or undefined system behavior.
I want to mention a few things about this code that generated some problems along the way: The struct auth declared at line 7 and struct auth * auth at line 12 share the same name, which results in problems when using malloc at line 25, which (in my case at least) allocates 4 bytes of memory instead of 36 bytes because it gets the size of struct auth * auth from line 12 instead of struct auth at line 7. I’ll show this in more detail in the solution section of this post.
This program accepts some commands and acts accordingly. There are 4 commands: “auth”, “reset”, “service” and “login”. “auth” is used for user authentication that is in this case a definition of the struct auth (ideally). “reset is used to free the memory allocated for struct auth (ideally), “service” is used for setting up a fictional service that is in this case only a copy of a given string. “login” is used to perform authentication of the user by checking if the auth member of struct auth structure is set (another bad practice of writing code).
Solution
Solution steps:
- Allocate memory for struct auth using “auth” command.
- Free memory allocated in step 1 by using “reset” command.
- Provide sufficiently large input using “service” command such that it will overflow the auth member of struct auth allocated previously at the same space where service string will now reside.
- Perform authentication by issuing the “login” command which will use the pointer that points to memory which was previously unallocated (this is where use-after-free happens).
After loading the program in GDB and disassembling it using Intel syntax, the useful breakpoints we could set are: After “auth” command sets-up the user structure (struct auth ideally) at main + 205, after “reset” deallocates memory at main + 250, after “service” allocates memory for the new string and places it there at main + 297 and after “auth” which will log us in if we did everything right at main + 346.
Step 1: First we issue the command “auth USER” which will allocate memory for struct auth (ideally) and set it’s name to “USER”. Note that the auth integer attribute remains unchanged and it’s set to 0.

Image 1: Allocated “USER” sting in memory
Image 1 shows how the things look in memory after we issue the mentioned command. But something’s wrong. Allocated memory where we are allowed to write is located at 0x8189818 as saved in EAX register (return value of malloc), but after printing few bytes before that (starting at 0x8189810), the chunk header shows that there are only 16 bytes allocated (this is from 0x00000011 where the LS bit is a flag pointing out that the previous chunk is allocated) instead of required 36 bytes for the struct auth. The reason for this is because at line 25, the malloc call gets the size of the pointer named the same as the structure, and because every pointer is 4 bytes in size, malloc allocates 4 bytes plus the additional 8 bytes for the header and another 4 bytes required for alignment (I guess it’s for the alignment according to some minor research on Stackoverflow and such).
Step 2: In this step we will “reset” (deallocate) the allocated memory in the previous step.

Image 2: deallocating memory
Image 2 shows that when we deallocate the memory allocated in the previous step, it still contains the contents we had there before it was deallocated, that is the “USER” string. After deallocation, the freed memory is now available for allocating it again, and this is exactly what we will do in step 3.
Step 3: By issuing the “service” command 3 times, giving different arguments each time: “AAAABBBB”, “CCCCDDDD” and “EEEEFFFF” we can see that it got written in the deallocated space from the previous step (0x8189818). By 3 times calling the “service” command, we also get 3 chunk headers because those are 3 separate allocations (one for each “service” command).

Image 3: successful exploitation of use-after-free vulnerability
Image 3 shows how new strings are written in memory. Another programming error occurred at line 35 where the space character is also taken as the part of the string (that’s the reason why there are 0x20 bytes at the beginning of each word).
Step 4: Referencing to image 3, we can see that the login command was issued. By issuing the “login” command, we can see that the program tries to access address previously stored in struct auth * auth pointer, which still exists in that pointer, but it’s memory got deallocated (and later replaced with the strings we provided by issuing “service” command). The code in “login” command at line 38 tries to access address *(auth + 32) which will result at accessing content at address 0x8189834 and because this is the location of the heap chunk header size of the memory chunk that contains “EEEEFFFF”, it will be populated with some data (the size of allocated memory) and result in a value different than 0 which will result in the program granting us access to the account created earlier.
Thanks for reading!