[Heap] Double Free 취약점
System/System Hacking

[Heap] Double Free 취약점

728x90

◾ 실습 환경: Ubuntu 16.04 (glibc 2.23)

Double Free와 U-A-F 취약점은 C 언어에서 동적 메모리를 관리를 올바르지 않은 방식으로 했을 때 발생하는 취약점들이다.

Double Free

해제된 메모리를 다시 한 번 해제하는 취약점이다.

📌 힙을 할당했다가 해제하면서 할당되었던 힙 청크의 주소가 크기에 맞는 bin (fastbin/unsorted bin/samllbin/largebin)에 들어가고, 같은 bin에 해당되는 크기로 재할당 요청이 오면 순차적으로 할당이 된다. 이 때, double free가 발생해 중복된 주소가 bin에 들어가게 되었을 때, 같은 크기로 할당 요청이 여러 번 들어오게 되면 동일한 메모리에 두 개의 객체가 할당될 수 있다. 이 점을 이용해 이미 해제된 힙 청크의 메타데이터를 조작하는 등 실행 흐름을 바꿀 수 있게 된다.

예제 -(1) df1: Double Free 확인하기

#include <stdio.h>
#include <malloc.h>
int main(void) {
    char* a = (char *)malloc(100);
    char *b = (char *)malloc(100);
    memset(a, 0, 100);
    strcpy(a, "Hello World!");

    memset(b, 0, 100);
    strcpy(b, "Hello Pwnable!");

    printf("%s\n", a);
    printf("%s\n", b);

    free(a);
    free(b);

    free(a);
}

△ df1.c

: 각 100byte씩 메모리를 할당하고 할당된 메모리에 각각 "Hello World!"와 "Hello Pwnable!"이라는 문자열을 복사하고 출력하는 코드이다.

→ 가장 마지막 코드에서 이미 해제된 메모리 a를 한 번 더 free()를 호출해 해제한다.

실제로 컴파일해서 실행했을 때 어떠한 문제없이 정상적으로 종료된다. 즉, 해제된 메모리를 다시 해제하는 것이 가능하다는 점을 확인할 수 있다!

char* a = (char *)malloc(100); 에서 메모리를 할당하면서 포인터 변수인 a에 할당했을 특정 힙 메모리의 주소가 저장된다. free(a); 를 해주면서 시스템의 힙 메모리 할당자의 구현에 따라 메모리가 해제되는데, 이 때 같은 포인터를 두 번 해제하는 비정상적인 일이 발생하면서 공격자가 프로그램을 예상치 못한 실행 흐름으로 만들 수 있다.

예제 - (2) dfb1 : Double Free 방지하기 (ptmalloc2에서)

#include <stdlib.h>
int main()
{
    char* ptr = malloc(32);
    char* ptr2 = malloc(32);

    free(ptr);
    free(ptr);
    return 0;
}

△ dfb1.c (dreamhack에서는 포인터마크인 *이 빠져있다!)

(Ubuntu 18.04(glibc 2.27)에서는 위와 같은 에러가 발생하지 않았다! __ 혹시 잘못된 거라면 알려주세요..!!!)

📌 (Double Free 발생원인)double free or corruption (fasttop)의 에러가 발생하는 원인은

if (__builtin_expect (old == p, 0)
{
       errstr = "double free or corruption (fasttop)";
      goto errout;
}

ptmalloc2 할당자에 double free를 방지하기 위해 동일한 힙 청크를 연속으로 여러 번 해제할 수 없도록 한 코드가 있기 때문이다.

old(이전에 해제한 힙 청크의 포인터)와 p(현재 해제할 힙 청크의 포인터)가 같다면 errstr을 출력하고 errout 비정상 종료한다.

예제 - (3) : Double Free 검증 우회하기

#include <stdlib.h>
int main()
{
    char *ptr = malloc(32);     // 0x602010 
    char *ptr2 = malloc(32);    // 0x602030

    free(ptr);
    free(ptr2);
    free(ptr);
    return 0;
}

△ dfb2.c (double free를 검증하는 파트를 우회하는 코드)

두 번째로 ptr을 free하는 부분에 breakpoint를 걸고 실행했을 때 heap의 구조를 살펴보면 아래와 같다.

이 때는 아직 double free가 발생하기 전이다.

fastbin[0] fastbin[1]
0x0 0x602000 -> 0x602030 -> 0x0

이제 두 번째 free(ptr)을 실행시켜 double free가 발생하도록 하고 heap 구조를 다시 살펴보면 아래와 같다.

fastbin[0] fastbin[1]
0x0 0x602030 -> 0x602000 -> 0x602030

ptr을 한 번 더 해제한 fastbin freelist에 중복된 주소가 들어가는 것을 알 수 있다.

⇒ fastbin에서 double free가 발생하고 같은 bin의 크기로 할당 요청이 들어온다면 0x602030, 0x602000, 0x602030에 순차적으로 힙을 할당해 두 개의 객체가 하나의 메모리(0x602030)를 사용할 수 있게 된다.


Double Free 버그에 대한 이해를 했으니 이제 Double Free를 이용한 기본적인(?) 공격방법에 대해 공부해보자!

▶ Fastbin Dup

▶ Fastbin Dup Consolidate

(추가 예정....)

SMALL

'System > System Hacking' 카테고리의 다른 글

[Heap] The House of Spirit  (0) 2020.09.30
[Heap] UAF(Use-After-Free)  (0) 2020.09.19
[Heap] Security Check  (0) 2020.09.13
[Heap] ptmalloc2  (0) 2020.09.12
Return to csu (ft. Return-to-vuln, Just-In-Time Code Reuse)  (0) 2020.08.15