ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • bin, chunk, double free
    보안개론 2024. 6. 3. 17:03

    glibc Heap

    malloc, free 관련

     

    bin - 뚜껑이 달려있는 저장통, 상자, 쓰레기통 ..

    어쨌든 용량이 다른 여러 종류의 통

    힙에서 해제가 된 메모리 청크를 관리하기 위해 사용하는 자료구조

     

    힙에서는 청크가 메모리를 할당하거나 해제하는 단위

    malloc : 메모리를 청크 단위로 할당해줌

    free : 사용이 끝난 메모리를 해제

     

    해제된 청크는 해당되는(사이즈 맞는) 빈에 저장되는데,

    각 빈은 서큘러 더블리 링크드 리스트 형태

     

    할당된 청크

    Meta Data
    User Data
    Meta Data

    사용자 데이터가 있고, 메타 데이터가 앞 뒤로 있음

    각각의 청크는 사용자 데이터 뿐만 아니라 관련 메타데이터도 포함함

     

     

    해제된 청크

    Chunk Size A M P
    Fwd Pointer
    Bck Pointer
    FD_Nextsize
    Bck_NextSize
    [ ... ]
    Prev_Size

    해제되면 유저 데이터는 필요 없음

    해당 부분이 포워드 포인터, 백 포인터, 포워드 사이즈, 백 사이즈를 나타내도록 바뀜

    그리고 자신의 청크 사이즈, 자기 앞 청크 사이즈를 가짐

     

    비트

    A: Allocated Arena 

    - 1로 설정시 mmap'd 메모리로부터 온 것

    - 0이면 메인 아레나 또는 메인 힙으로부터 왔음

     

    M: Mmap'd chunk

    - mmap 콜에 의해 할당되었다

    -> 힙의 일부가 아니다

     

    P: Previous chunk is in use

    - 물리적으로 인접한 앞 쪽 청크가 사용중인가 아닌가

     

     

    메모리는 malloc 혹은 mmap에 의해 관리됨

    사용이 끝나면 해제되어 bin에 매달림

    이때 bin은 여러 유형이 있음

    small bin - 62

    large bin - 63

    unsorted bin - 1

    fast bin - 10

    tcache bin - 64

     

    small, large, unsorted bin은 옛날부터 있었음

    fast, tcache bin은 비교적 최신, 최적화됨

     

    패스트빈은 스몰 빈과 비슷하게 고정된 청크 사이즈만을 다룸

    16, 24, 32, 40, 48, 56, 64, 72, 80, 88 바이트

     

    청크 사이즈가 16바이트면 패스트 빈 1에 매달리게 됨

    사용자가 20바이트 요청 -> 패스트 빈 2에 매달리게 됨

    4바이트는 사용 안되지만 이렇게 할당하면 속도가 빠름

     

     

    어쨌든 빈은 프리된 메모리 청크를 관리하는 자료구조

    링크드 리스트로, LIFO 방식으로 관리됨

    새로 해제되면 탑에 매달리고, 오래전에 해제된 청크는 바텀에 있음

    여기서 malloc 요청이 있으면 탑에 있던 청크가 할당이 됨

     

    #define link(bin, P) {
        chk = bin->fd;	// 원래 탑에 있었던 청크 == chk
        bin->fd = P;
        P->fd = chk;
        chk->bk = P;
        P->bk = bin;
    }
    
    #define unlink(P, BK, FD) {
        FD = P->fd;		// 앞 뒤로 연결해주면 
        BK = p->bk;		// 가운데 있던 청크는 연결 끊김
        FD->bk = BK;
        BK->FD = FD;
    }

     

    청크

    포워드 포인터: 자기보다 먼저 해제된 포인터를 가리킴

    백 포인터: 자기보다 나중에 해제된 청크의 포인터

     

    ** 청크 사이즈를 저장하는 이유: 물리적으로 인접한 링크가 해제되면 통합하기 위해

    ** 왜 통합을 하는가 - 프레그멘테이션을 피하기 위해


    비어있는 bin의 모습

     

    청크가 하나 들어온(프리된) bin의 모습

     

    Double Free

    Chunk1을 두 번 프리한 경우이다.

    이후 malloc을 통해 Chunk1을 할당받아도 Chunk1의 포워드 포인터가 자기 자신을 가리키기에

    Chunk1이 계속 bin에 남아있게 되고, malloc을 통해 계속 같은 메모리를 할당받게 된다.

     

    더블 프리 취약점

    CWE-415

    같은 메모리 주소가 두 번 프리되면 생기는 문제

    어떤 프로그램이 같은 인자를 가지고 두 번 프리하면 bin이 망가지게 됨

     

    같은 청크가 여러번 할당될 수 있게 됨

    a = malloc(10);	// 0xa04010
    b = malloc(10);	// 0xa04030
    c = malloc(10);	// 0xa04050
    
    free(a);
    free(b);
    free(a);
    
    d = malloc(10);	// 0xa04010
    e = malloc(10);	// 0xa04030
    f = malloc(10);	// 0xa04010

    * a - b - a 순으로 더블 프리 시도를 한 이유

    두 번 연속으로 프리 시도 시 탐지하고 막음

    그래서 중간에 다른 청크를 끼워넣음

    -- fastbin의 탑에서 같은 청크가 추가로 삽입되려고 하면 문제가 있다고 판단

     

    위 코드에서는 d와 f가 같은 청크를 할당받게 됨

     

     

    #include <stdio.h>
    #include <malloc.h>
    
    int main() {
        char *a = (char *)malloc(10);
        char *b = (char *)malloc(10);
        char *c = (char *)malloc(10);
        
        free(a);
        free(c);
        free(b);
        free(c);
        
        return 0;
    }

     

    위 코드의 경우 bin이 c와 b가 계속해서 할당되도록 망가지게 됨

    여기서 malloc d, e, f

    d: c할당

    e: b할당

    f: c할당

     

    영향

    Integrity, Confidentiality, Availability

    메모리 변조, 인가되지 않은 코드나 커맨드 실행

     

Designed by Tistory.