본문 바로가기

시스템해킹/개념

Double Free bug와 Fastbin dup 복습

어제부로 종강했는데, 그 동안 CTF 관련 내용들을 너무 복습하지 않아 까먹은 부분이 있어서 다시 복습할 겸 글을 적습니다.

Double Free Bug

말 그대로, Free를 두 번 시켜서 발생되는 취약점입니다. 

// gcc -o tcache_dup tcache_dup.c -no-pie
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

char *ptr[10];

void alarm_handler() {
    exit(-1);
}

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    signal(SIGALRM, alarm_handler);
    alarm(60);
}

int create(int cnt) {
    int size;

    if (cnt > 10) {
        return -1;
    }
    printf("Size: ");
    scanf("%d", &size);

    ptr[cnt] = malloc(size);

    if (!ptr[cnt]) {
        return -1;
    }

    printf("Data: ");
    read(0, ptr[cnt], size);
}

int delete() {
    int idx;

    printf("idx: ");
    scanf("%d", &idx);

    if (idx > 10) {
        return -1;
    }

    free(ptr[idx]);
}

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

int main() {
    int idx;
    int cnt = 0;

    initialize();

    while (1) {
        printf("1. Create\n");
        printf("2. Delete\n");
        printf("> ");
        scanf("%d", &idx);

        switch (idx) {
            case 1:
                create(cnt);
                cnt++;
                break;
            case 2:
                delete();
                break;
            default:
                break;
        }
    }

    return 0;
}

이 코드는 Double Free Bug 취약점이 있는 코드다. 만약 여기서 할당받은 메모리를 두 번 Free시킬 수 있다면, Double Free Bug가 발생해서 메모리가 연속적으로 이어지게 됩니다. 그런데, Dockerfile을 보면 버전이 ubuntu 18.04 버전입니다.

이 glibc 버전에서는 Double Free Bug Detection이 존재하지 않으므로, 단순하게 free를 두 번해서 Double Free Bug를 일으킬 수 있습니다.

 

Double Free Bug로 같은 메모리를 두 번 해제하면, 두 메모리는 서로 연결된 채로 유지됩니다. 즉, 이 메모리는 free가 되어 있는 상태이면서 할당이 될 수 있는 상태인 것입니다.

 

따라서, 만약 계속해서 할당을 하게 되면, 앞에서 할당한 값을 뒤에서 할당한 값으로 덮어씌울 수 있습니다.

-> 그러므로, 만약 puts_got을 앞에 넣어줬다면, 그 주소에 쓸 값을 뒤에 넣어주면 그 값으로 덮어 씌울 수 있는 것입니다.

 

그러나, 버전이 올라가면서 Double Free Bug Detection 부분이 추가가 된다면, 단순히 Double Free를 시켰을 때 오류가 발생합니다. Free된 메모리에 특정 키를 저장해서, 그 키가 그대로 유지되어 있을 때 Free를 하게 되면 Double Free가 되었음을 인지하고,  오류를 발생시키기 때문입니다.

 

따라서, 만약 해제된 메모리에 접근해서 내용을 수정할 수 있다면, 검사 키를 수정할 수 있게 되고, 그러면 다시 한 번 Double Free Bug를 일으킬 수 있게 됩니다.

 

Fastbin Duplication

그러나, Double Free Bug는 glibc 버전이 상승되면서 점차 우회하기 어려워졌습니다. 이에 대한 대응 방안으로 Fastbin Duplication이 등장하였습니다.

 

핵심 아이디어는 같은 chunk를 두 번 이상 Fastbin에 넣지 않고도 Fastbin 리스트 안에 같은 주소, 또는 조작한 주소를 의도적으로 두 번 삽입해서, 나중에 malloc()할 때 원하는 주소를 중복으로 리턴받게 하는 기법입니다.

 

먼저 tcachebins를 꽉 채워주어야 하는데, tcachebins는 총 7개입니다. 이들을 malloc과 free를 반복해서 꽉 채워줍니다.

이렇게 하면 fastbin까지 사용이 됩니다. 이제 여기서 fastbin 두 개를 연결되게 할 수 있다면 Double Free Bug를 일으킬 수 있게 됩니다.

 

추후에 Fastbin Dup같은 경우는 더 자세하게 공부해서 올리도록 하겠습니다.