일요일, 7월 17

Protostar Heap3

Protostar Heap3

이 글은 Exploit-exercises.com의 Protostar heap3에 대한 내용을 담고 있다. 


Double linked list의 구조

Double linked list 는 각 node마다 이전 노드의 주소와 다음 노드의 주소를 저장하는 형태의 자료구조입니다.


Double linked list를 이용해 exploit 하는 방법. 


Double linked list에서 하나의 node를 삭제한다고 생각해보죠.
Double linked list(이하 DL)에서 하나의 노드를 삭제하기 위해서는 해당 노드의 주소를 가지고 있는
이전 노드가 가진 다음 노드의 주소, 그리고 다음 노드가 가지고 있는 이전 노드의 주소를 변경해야 합니다.

예를 들어, A=B=C 에서 B를 삭제한다면,
(B.nextnode).prevnode = B.prevnode ( 결과, A=B C-A)

(B.prevnode).nextnode = B.nextnode ( 결과, C=A )

하지만 만약 힙 오버플로우 같은 상황을 만나 B가 가진 nextnode나 prevnode값이 변경되면 어떻게 될까요? 

[가정] B의 nextnode, prevnode가 0xaaaaaaaa, 0xbbbbbbbb로 변경되었을 경우. 
(B.nextnode).prevnode = B.prevnode 
=> 0xaaaaaaaa.prevnode = 0xbbbbbbbb

(B.prevnode).nextnode = B.nextnode 
=> 0xbbbbbbbb.nextnode = 0xaaaaaaaa
즉, 변조된 B의 nextnode 주소에 있는 prevnode값을 변조된 B의 prevnode로 변경할 수 있다는 뜻입니다.


malloc double link list 구조체 
struct malloc_chunk {
INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */
INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */

struct malloc_chunk* fd;         /* double links -- used only if free. */
struct malloc_chunk* bk;

/* Only used for large blocks: pointer to next larger size.  */
struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
struct malloc_chunk* bk_nextsize;
};

문제가 될 수 있는 malloc의 소스(부분)

if (!prev_inuse(p)) {
    prevsize = p->prev_size;
    size += prevsize;
    p = chunk_at_offset(p, -((long) prevsize));
    unlink(p, bck, fwd);
}

unlink 시에 동작.

/* Take a chunk off a bin list */
#define unlink(P, BK, FD) {                                            \
    FD = P->fd;              \
    BK = P->bk;              \
    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))        \
      malloc_printerr (check_action, "corrupted double-linked list", P);      \
    else {              \
        FD->bk = BK;             \
        BK->fd = FD;             \
        if (!in_smallbin_range (P->size)          \
            && __builtin_expect (P->fd_nextsize != NULL, 0)) {        \
     if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0)       \
  || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))    \
       malloc_printerr (check_action,          \
          "corrupted double-linked list (not small)", P);\
            if (FD->fd_nextsize == NULL) {          \
                if (P->fd_nextsize == P)          \
                  FD->fd_nextsize = FD->bk_nextsize = FD;        \
                else {             \
                    FD->fd_nextsize = P->fd_nextsize;         \
                    FD->bk_nextsize = P->bk_nextsize;         \
                    P->fd_nextsize->bk_nextsize = FD;         \
                    P->bk_nextsize->fd_nextsize = FD;         \
                  }             \
              } else {             \
                P->fd_nextsize->bk_nextsize = P->bk_nextsize;        \
                P->bk_nextsize->fd_nextsize = P->fd_nextsize;        \
              }              \
          }              \
      }               \
}

Heap3 의 메모리 구조. 
------------ a ----------------------
| prev_size (4 bytes) |
---------------------------------------
| size (4 bytes) |
---------------------------------------
| data (32 bytes) |
---------------------------------------
------------ b ----------------------
| prev_size (4 bytes) |
---------------------------------------
| size (4 bytes) |
---------------------------------------
| data (32 bytes) |
---------------------------------------
------------ c ----------------------
| prev_size (4 bytes) |
---------------------------------------
| size (4 bytes) |
---------------------------------------
| data (32 bytes) |
---------------------------------------


실제로 공격에 사용되는 코드 


공격 대상 물색 
-. Stack return address
스택에 들어있는 리턴어드레스는 친숙한 공격 대상이지만, 지역변수를 오버플로우 시키는 경우처럼 스택의 주소에 신경쓰지 않아도 되는 경우 외에는 주소가 랜덤으로 변하기 때문에 제외했다.
-.dtors
elf 포맷에는 프로그램이 종료될 때 .dtors에 등록된 함수들을 실행시킨다. 고정 주소 값이라고 생각했는데, 이상하게 동작하지 않아서 pass;;
-. GOT
elf 포맷은 이미지 로드시 사용하는 함수들을 GOT에 연결시켜준다. 고정 주소를 사용하므로 좋은 공격 대상이다. 


공격 code



결과