Exploiting Integer overflow and UAF using Radare2
Dragon is a rookie challenge in pwnable.kr. Its a RPG game that allows you to fight against dragons. The game seems impossible to beat; at least in the first few tries.
I made a RPG game for my little brother.
But to trick him, I made it impossible to win.
I hope he doesn't get too angry with me :P!
Author : rookiss
Download : http://pwnable.kr/bin/dragon
Running at : nc pwnable.kr 9004
The first few runs we recognize that its impossible to beat:
Welcome to Dragon Hunter!
Choose Your Hero
[ 1 ] Priest
[ 2 ] Knight
1
Baby Dragon Has Appeared!
[ Baby Dragon ] 50 HP / 30 Damage / +5 Life Regeneration.
[ Priest ] 42 HP / 50 MP
[ 1 ] Holy Bolt [ Cost : 10 MP ]
Deals 20 Damage.
[ 2 ] Clarity [ Cost : 0 MP ]
Refreshes All Mana.
[ 3 ] HolyShield [ Cost: 25 MP ]
You Become Temporarily Invincible.
1
Holy Bolt Deals 20 Damage To The Dragon!
But The Dragon Deals 30 Damage To You!
And The Dragon Heals 5 HP!
[ Baby Dragon ] 35 HP / 30 Damage / +5 Life Regeneration.
[ Priest ] 12 HP / 40 MP
[ 1 ] Holy Bolt [ Cost : 10 MP ]
Deals 20 Damage.
[ 2 ] Clarity [ Cost : 0 MP ]
Refreshes All Mana.
[ 3 ] HolyShield [ Cost: 25 MP ]
You Become Temporarily Invincible.
3
HolyShield! You Are Temporarily Invincible...
But The Dragon Heals 5 HP!
[ Baby Dragon ] 40 HP / 30 Damage / +5 Life Regeneration.
[ Priest ] 12 HP / 15 MP
[ 1 ] Holy Bolt [ Cost : 10 MP ]
Deals 20 Damage.
[ 2 ] Clarity [ Cost : 0 MP ]
Refreshes All Mana.
[ 3 ] HolyShield [ Cost: 25 MP ]
You Become Temporarily Invincible.
1
Holy Bolt Deals 20 Damage To The Dragon!
But The Dragon Deals 30 Damage To You!
And The Dragon Heals 5 HP!
You Have Been Defeated!
Choose Your Hero
[ 1 ] Priest
[ 2 ] Knight
1
Mama Dragon Has Appeared!
[ Mama Dragon ] 80 HP / 10 Damage / +4 Life Regeneration.
[ Priest ] 42 HP / 50 MP
[ 1 ] Holy Bolt [ Cost : 10 MP ]
Deals 20 Damage.
[ 2 ] Clarity [ Cost : 0 MP ]
Refreshes All Mana.
[ 3 ] HolyShield [ Cost: 25 MP ]
You Become Temporarily Invincible.
Priest has 3 abilities and Knight has 2. Priest has more survivability. It has a “Sheild” ability; that renders him invincible for the next move. Dragons always attack and has regen.
Baby dragon starts at 50 HP and +5 regen with 30 damage.
Mama dragon stars at 80HP and +4 regen with 10 damage.
We need to somehow deal damage and goal is to reduce the dragon’s HP to 0.
Lets check out the flow of the program using radare2.
root@vm1adogratest:~# r2 -d dragon
Process with PID 19814 started…
PID = 19814
r_debug_select: 19814 19814
[0xf7701a20]> af
[0xf7701a20]> s main
[0x0804868d]> pdf

Lets break at the start of sym.PlayGame
[0x0804888d]> db sym.PlayGame
[0x0804888d]> dc
Welcome to Dragon Hunter!
[0x080486f8]>
Lets get into Visual mode and checkout the disassembly.

At the top we have a bunch of checks that checks if you chose a character between Priest and Knight. There is a secretLevel which you are redirected to if you press 3.
Lets check out what’s the secretLevel all about, maybe our flag is there:

It asks for a password, compares it with “Nice_Try_But_The_Dragons_Wont_Let_You”. The thing to note is that we are just reading 10 bytes from the input using scanf.
| 0x08048d95 8d45ea lea eax, [ebp-0x16]
| 0x08048d98 89442404 mov [esp+0x4], eax
| 0x08048d9c c704242f930. mov dword [esp], str.10s
| 0x08048da3 e8d8f7ffff call 0x108048580 ; (sym.imp.__isoc99_scanf)
There is no easy way to defeat such checks as scanf will stop reading after exactly 10 bytes or newline whichever occurs first. So we cant enter the correct password, such a cheeky author. Lets get back to playing the game and designing a strategy on how to defeat the dragon.

In the beginning we see 2 mallocs. Probably used to save the data-structure of these dragons. Mallocs are 0x10 in size. That suggests the program uses 16 bytes to save data of each dragon.
Initializing the data structures:
| | 0x08048777 8b45f0 mov eax, [ebp-0x10]
| | 0x0804877a c7400400000. mov dword [eax+0x4], 0x0
| | 0x08048781 8b45f0 mov eax, [ebp-0x10]
| | 0x08048784 c6400832 mov byte [eax+0x8], 0x32
| | 0x08048788 8b45f0 mov eax, [ebp-0x10]
| | 0x0804878b c6400905 mov byte [eax+0x9], 0x5
| | 0x0804878f 8b45f0 mov eax, [ebp-0x10]
| | 0x08048792 c7400c1e000. mov dword [eax+0xc], 0x1e
| | 0x08048799 8b45f0 mov eax, [ebp-0x10]
| | 0x08048799 8b45f0 mov eax, [ebp-0x10]
| | 0x0804879c c700058d0408 mov dword [eax], sym.PrintMonsterInfo
ebp-0x10 and ebp-0x14 are locations of pointers to heap which contains the dragon’s data structure. 0x32 is 50 which is also the HP of baby dragon, stored at an offset of (+0x8). 0x5 is regen which is stored at an offset of (+0x9). Its obvious that only one byte is used to store the HP of the dragon. It stores the damage at 0xc. Also interestingly the data structure stores the function pointer to sym.PrintMonsterInfo at offset (+0x0). This suggests the program calls this function pointer to print the monster information. We can think about taking over this pointer to hijack the execution flow of this program.
As dragons have regen, its possible for us to make the dragon cross 125+ HP and overflow to a negative number which defeats the unsigned check at the end of the program.
Lets checkout sym.PriestAttack:

Lets move to the interesting part at the end of this function.

Here you can see it adds the regen of the dragon onto the HP variable at (+0x8) with movzx (sign extension). After the HP of the dragon is 0 or the Priest has hp of 0 it gets out of the function and frees the dragon pointers.

After frees and on win condition, we would end up here:

In the end after defeating the dragon we get a prompt to enter ourselves onto the leaderboard (supposedly).
The interesting thing to note is we recently freed the dragon objects. Through fastbin in libc, the recently freed memory is reused and returned again if the fastbin size matches. We malloc again for 0x16 bytes to store the name of the person, but it will reuse the pointer used to store dragon’s attributes.
This is Use After Free. In the end it tries to print the dragon’s details that we defeated:
| | | 0x080488b4 c7042410910. mov dword [esp], str.AndTheDragonYouHaveDefeatedWasCalled
| | | 0x080488bb e860fcffff call 0x108048520 ; (sym.imp.puts)
| | | sym.imp.puts()
| | | 0x080488c0 8b45f0 mov eax, [ebp-0x10]
| | | 0x080488c3 8b00 mov eax, [eax]
| | | 0x080488c5 8b55f0 mov edx, [ebp-0x10]
| | | 0x080488c8 891424 mov [esp], edx
| | | 0x080488cb ffd0 call eax
it calls the function pointer at +0x0 offset of the memory we now have control over. As we already have a win function inside the SecretLevel we can redirect the execution flow to that call and bake us a freshly made shell :)
Here’s our final exploit. Lets run it and get the flag. You’ll see the exploit interactively plays the game with the server and in the end defeats the dragon and triggers a UAF to hijack execution flow.

We have a shell, and can cat the file to get the flag. I think the challenge was very well created; having a secretLevel totally blew me off for a couple of hours when I was trying to defeat scanf’s format descriptors. In the end it was very elegant to have a integer overflow lead to a UAF and finally shell. Very satisfying.
Pwnable: dragon using Radare2 was originally published in Aneesh Dogra’s Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.