This is a RPG that allow you to choose action and win the game. However, you cannot win this game unless using some tricks.
main:
puts("Welcome to Dragon Hunter!");
PlayGame();
PlayGame:
int PlayGame()
{
int result; // eax@1
while ( 1 )
{
while ( 1 )
{
puts("Choose Your Hero\n[ 1 ] Priest\n[ 2 ] Knight");
result = GetChoice();
if ( result != 1 && result != 2 )
break;
FightDragon(result);
}
if ( result != 3 )
break;
SecretLevel();
}
return result;
}
FightDragon:
void __cdecl FightDragon(int a1)
{
char v1; // al@1
void *v2; // ST1C_4@10
int v3; // [sp+10h] [bp-18h]@7
void *PLAYER_STRUCT; // [sp+14h] [bp-14h]@1
void *DRAGON_STRUCT; // [sp+18h] [bp-10h]@1
PLAYER_STRUCT = malloc(0x10u);
DRAGON_STRUCT = malloc(0x10u);
v1 = Count++;
if ( v1 & 1 )
{
*((_DWORD *)DRAGON_STRUCT + 1) = 1;
*((_BYTE *)DRAGON_STRUCT + 8) = 80;
*((_BYTE *)DRAGON_STRUCT + 9) = 4;
*((_DWORD *)DRAGON_STRUCT + 3) = 10;
*(_DWORD *)DRAGON_STRUCT = PrintMonsterInfo;
puts("Mama Dragon Has Appeared!");
}
else
{
*((_DWORD *)DRAGON_STRUCT + 1) = 0;
*((_BYTE *)DRAGON_STRUCT + 8) = 50;
*((_BYTE *)DRAGON_STRUCT + 9) = 5;
*((_DWORD *)DRAGON_STRUCT + 3) = 30;
*(_DWORD *)DRAGON_STRUCT = PrintMonsterInfo;
puts("Baby Dragon Has Appeared!");
}
if ( a1 == 1 )
{
*(_DWORD *)PLAYER_STRUCT = 1;
*((_DWORD *)PLAYER_STRUCT + 1) = 42;
*((_DWORD *)PLAYER_STRUCT + 2) = 50;
*((_DWORD *)PLAYER_STRUCT + 3) = PrintPlayerInfo;
v3 = PriestAttack((int)PLAYER_STRUCT, DRAGON_STRUCT);
}
else
{
if ( a1 != 2 )
return;
*(_DWORD *)PLAYER_STRUCT = 2;
*((_DWORD *)PLAYER_STRUCT + 1) = 50;
*((_DWORD *)PLAYER_STRUCT + 2) = 0;
*((_DWORD *)PLAYER_STRUCT + 3) = PrintPlayerInfo;
v3 = KnightAttack((int)PLAYER_STRUCT, DRAGON_STRUCT);
}
if ( v3 )
{
puts("Well Done Hero! You Killed The Dragon!");
puts("The World Will Remember You As:");
v2 = malloc(16u);
__isoc99_scanf("%16s", v2);
puts("And The Dragon You Have Defeated Was Called:");
(*(void (__cdecl **)(void *))DRAGON_STRUCT)(DRAGON_STRUCT);
}
else
{
puts("\nYou Have Been Defeated!");
}
free(PLAYER_STRUCT);
}
SecretLevel:
int SecretLevel()
{
char s1; // [sp+12h] [bp-16h]@1
int v2; // [sp+1Ch] [bp-Ch]@1
v2 = *MK_FP(__GS__, 20);
printf("Welcome to Secret Level!\nInput Password : ");
__isoc99_scanf("%10s", &s1);
if ( strcmp(&s1, "Nice_Try_But_The_Dragons_Won't_Let_You!") )
{
puts("Wrong!\n");
exit(-1);
}
system("/bin/sh");
return *MK_FP(__GS__, 20) ^ v2;
}
Our final goal is to get a shell. Since we notice that there is a shell when we enter secret level and enter the right password, let's review its code.
Obviously this cannot be done.Nice_Try_But_The_Dragons_Won't_Let_You!
is 39, but scanf
only read 16.
Maybe we have to defeat the dragon.
We can choose two types of role. One is priest
and the other is knight
. And there are 2 types dragons too, the Baby Dragon
and the Mama Dragon
. After comparing the attribute, we can find the Mama Dragon
is not as stronger as Baby Dragon
and these 2 appears alternately.
Priest has Holy Bolt
which will deals 20 damage, Clarity
which will refreshes all mana, HolyShield
that can let you become temporarily invincible.
Knight can Crash
to deals 20 damage, and Frenzy
to deals 40 damage but lose 20 too.
After calculating, we will definitely lose the battle. However, the variable saving dragon's life is only 1 byte which means the max life is 127.
So we can die one time to meet a weaker dragon, and use HolyShield
and Clarity
to let the dragon heal itself until it overflow and die.
After we win the game, the dragon will be freed, and the buffer of the same size will be applied to receive our input. And in the end, it will call the value saved at that the dragon's struct, so it's a UAF. Since both are 16, they are located at the same address.
We just input the shell's address to let it call and shell got.