Use After Free
One of my favorite challenges from the https://pwnable.kr wargame is Dragon, a small text based RPG game which contains some interesting hidden functionality. During the game you are given the option of playing a Priest or Knight who both have different abilities.
In both scenarios it is impossible to defeat the Dragon but before we dive into the application it is important to discuss some of the defenses that are put in place to protect binaries from exploitation. The first of these protection is ASLR which is Address Space Layout Randomization. This protection is used to randomly offset the location of modules and memory based structures to prevent shellcode execution. This is incredibly effective at mitigating some buffer overflow exploits as an adversary is no longer able to reliably jump to a vulnerable function in memory. The keyword here is reliably since ASLR still allows the adversary to guess the locations of these randomly placed areas. To prevent against this a high amount of entropy should be used to generate more random offsets. The next defense that is important to us is DEP or Data Execution Protection. This defense is used to mark certain regions of memory sectors such as the stack as being non-executable. This means that if we wanted to inject shellcode into a vulnerable location within a marked sector it will be unsuccessful in executing. Now we notice that both DEP and ASLR is enabled on the system that is running the challenge application so we must keep this in mind when we are searching for a vulnerability. With this out of the way let’s begin reverse engineering the application.
When you open an ELF binary in Binary Ninja you are immersed into an environment that allows you to navigate the binary in an organized and intuitive manner. The first function that you enter is called _start and is typically the entry point for the binary. This function is not particularly interesting and is usually used to call the main function. By clicking on either the main function in the left function panel or clicking on the main call in the ELF graph we can navigate to the contents of main.
Here see that nothing more than a intro banner being displayed and a function call to PlayGame. Just like our last buffer overflow endeavour I strongly recommend documenting the progress we have made by forward engineering the source code. This will appear as follows:
main(){
puts("Welcome to Dragon Hunter!");
PlayGame();
}
Next we will check out the PlayGame function.
The beginning of this function handles the character selection but we discover that by entering 3 we can call the hidden SecretLevel function.
We find out that we need a password so let’s see what we can find in the SecretLevel function.
![Secret Function ASM][secretfunction]
We discover that after entering the correct password we can get a shell, however there appears to be no way we can enter Nice_Try_But_The_Dragons_Won’t_Let_You! since we are only creating a space of 0x16 for the scanf function. Let’s continue to forward engineer the program with what we have found.
int PlayGame(){
int result;
puts("Choose your Hero\n[1] Priest\n[2] Knight");
Result = GetChoice();
If ( result == 1 || result == 2){
FightDragon(result);
}
else if (result == 3){
SecretLevel();
}
}
int SecretLevel(){
char pass[16];
printf("Welcome to Secret Level!\nInput Password : ");
scanf(%s, pass);
if(strcmp(pass, "Nice_Try_But_The_Dragons_Won't_Let_You!")){
puts("Wrong!\n")
exit(1);
}
system("/bin/sh")
}
Now it is time to observe the FightDragon function.
Here we notice that two objects are being malloced for at the very beginning. After some digging I noticed that offsets were being used on these objects to retrieve data. Incidentally these objects were associated with either a dragon or the player so using ctrl-n I was able to rename all instances of the variable within Binary Ninja. This is a vital technique as it allows you to easily reference a multitude of variables and thoroughly understand what each of them means.
After allocating space for the two structs we notice that there is a counter which is being used to select which dragon the player will fight. After playing the game another time I noticed that after defeating a baby dragon I would be tasked with fighting a mama dragon. This is where we start to notice something very interesting.
So it appears that the values in the assembly are the stats for the dragon. If we look very closely at the line that I highlighted we can see that only 4 bits were used to store the health of the dragon. This reveals that the absolute maximum health the dragon can have is 127 (1 1 1 1 if all bits are on we get 127 in decimal). With this information I started to speculate if I could instead use the Dragon’s health regeneration to overflow the integer and force it to 0. This concept is observed in the following image.
Integers should be thought of as this wheel. If a number is increased to it’s maximum it will simply start the cycle all over again. Let’s pair the priest’s invincibility spell with the Dragon’s health regeneration to see if we can make this work.
We successfully discovered how to defeat the Dragon but we still want our shell.
When we observe the PriestAttack function we notice that regardless of what happens the Dragon struct is freed. However if the game is won we see the following:
At first I thought it was re mallocing another Dragon struct but instead it is actually mallocing for the players name. This means that even though the Dragon struct was freed in the PriestAttack function the program is still using the struct. This combination of events introduces a use after free vulnerability.
By inserting the location of what line we want executed as the player name we can call whatever part of the code we want. In particular we want access to the shell that was found in SecretLevel. We are going to need write some clever python in order to exploit this so I will use a CTF optimized library called pwntools (https://pwntools.readthedocs.io/en/2.2/about.html) to write a quick exploit.
In this script we first connect to the pwnable.kr site. Then we proc the event for the mother dragon by spamming ones. Then we defeat the mother dragon by overflowing the integer. Once we the dragon is defeated we send the location of the SecretLevel function call to a shell and proceed to make it interactive.
##Conclusion##
While this series only covered a couple of vulnerabilities, exploits, and strategies I hope that it still produced a useful starting point for those entering the field of binary exploitation. We discovered that it is important to layout a malleable plan of exploration when working with a binary as this will provide structure to the overall discovery process. As you traverse the binary you will learn new things which will cause you to think differently about the overall problem and potentially modify your plan. It is also important to have a good understanding of how the binary was first engineered by writing what you believe the source code may have looked like. This will allow you to visualize the problem more thoroughly and quickly spot locations that may produce vulnerabilities that you can exploit. As a final bit of advice I encourage newcomers to be patient and take the harder route to the solution. While it may be tempting to quickly look up a solution to the entirety of a problem, you will surely learn more by struggling and exploring all of the crevices that surround the issue.
- Reverse Engineering (2) ,
- Exploitation (2) ,
- Development (3) ,
- Vulnerabilities (2) ,
- Free After Use (2)