본문 바로가기

공부는 계속 ../Pwnable Writeup

Double Free Bug

이제 heap overflow 에 관련해서 공부를 해볼까 한다.  heap 에 대한 공격은 여러가지가 있다.


그 중 제일 기본이 되는 Double Free bug


참조 : http://smleenull.com/586


여기나온 블로그 문서가 제일 올바르게 작성되었다. (다른 곳은 좀 이해하기가 너무 어려움.. 사실 이해할 수가 없다고 해야함)


smleenull 블로그 문서를 보면 대부분 이해가 될것이지만, 아래 부분에 대해서는 조금 추가 설명을 진행해야 되겠다.

 -> 특히나 chunk size 를 구하는(and 0xfffffffc) 매커니즘을 설명해놓은 문서는 여기밖에 없음


(위 그림에서 '다음 청크 포인터 + 다음 청크 사이즈' 를 변경 => '다음 청크 포인터 + 다음 청크 사이즈 + 4')




이제 위 정보를 바탕으로 공격 페이로드가 들어간 메모리 구조를 다시 보도록 하자.


free(mol1)이 동작하고 chunk_free() 에서는 '다음 청크(mol2)'가 top chunk가 아님을 확인했고, free chunk인지 확인하기 위해 다음과 같이 동작한다.


1. '다음 청크의 포인터' + '다음 청크의 사이즈(0xffffffff & 0xfffffffc = 0xfffffffc)' + 4 에 위치한 값의 PREV_INUSE 값 확인

2. 위 '1'번에서 다음 청크의 사이즈는 -4 이므로 다음과 같은 식이 나오게 된다.  ==>  [ '다음 청크의 포인터' - 4 + 4 ] = 제자리

3. 그럼 결국 제자리(mol1 청크의 prev_size 값)에 있는 값을 가지게 되고, 해당 위치를 '다음 청크' 라고 생각하고 해당 위치의 PREV_INUSE 값을 확인하게 된다. -> 여기서 '다음 정크'라고 함은 쉽게 생각해서 가상의 mol3 라고 생각하면 된다 (mol2가 mol3를 먹어버린 상황?) // 해당 위치는 mol3의 size라고 인식


4. 해당 값은 0xfffffffc 로 PREV_INUSE 값이 0 이므로 합병하기 위해 fake chunk의 fd, bk 값을 이용해 unlink() 를 수행하게 되어 우리가 원하는 곳에 값을 덮어쓸 수 있게 된다. -> 여기서 fd, bk 를 갖고 있는 fake chunk 는 mol2임 (fact, 가상아님!) -> mol2는 날라간게 아니라 연속된 주소에 바로 붙어 있음.. 이건 그냥 mol2를 여기다 할당해놓고 mol1이 오버플로된 상황임


5. 합병 후 '다음 청크의 사이즈' + mol1 chunk size 를 계산해 합병 된 mol1 chunk의 chunk size 부분에 새로운 합병 후 크기를 입력해 준다. 

( 0x19 + (-0x4) = 0x15 ) -> 여기서 다음 청크의 사이즈가 -4인 이유는 .. 여기서 이해가 안가 5시간동안 멍을 때렸음.. (결국 동아리 후배가 알려줌) -> 0xffffffff & 0xfffffffc = 0x4 로 실제 mol2의 크기 값임, 그리고 mol2의 fd, bk 의 값에 의존해서 mol1의 fd,bk 값을 적어줌


6. '다음 청크의 포인터' 를 fake chunk로 인식했기 때문에 해당 부분의 -4 위치를 prev_size 값으로 인지하여 해당 부분에 PREV_INUSE 값을 제외한 청크의 크기를 써줌 (0x00000014) -> 해당 위치는 mol3의 size 를 인식하고 있으므로, size 앞의 4바이트는 prev_size를 나타낸다. 여기서 prev_size는 mol1 + mol2 의 병합된 사이즈 임을 나타내므로 0x19 - 0x4 - 0x1 = 0x14 를 나타냄


병합 과정은 아래 코드를 참조하면 쉽게 이해할 수 있다. (출처 : 원재아빠 블로그)

http://www.hackerschool.org/HS_Boards/data/Lib_system/dfb_leon.txt


//test3.c #include <stdio.h> #include "dumpcode.h" main(int argc, char *argv[]) { char *mol1; char *mol2; char *mol3; mol1 = malloc(16); mol2 = malloc(16); mol3 = malloc(16); if ( argc< 2) { fprintf(stderr, "error args\n" ); exit(0); } strcpy( mol1 , argv[1] ); strcpy( mol2 , argv[2] ); strcpy( mol3 , argv[3] ); dumpcode(mol2-28,64); free(mol1); dumpcode(mol2-28,64); free(mol2); dumpcode(mol2-28,64); free(mol3); } $./test3 AAAA BBBB CCCC 0x08049ab4 19 00 00 00 41 41 41 41 00 00 00 00 00 00 00 00 ....AAAA........ 0x08049ac4 00 00 00 00 00 00 00 00 19 00 00 00 42 42 42 42 ............BBBB 0x08049ad4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x08049ae4 19 00 00 00 43 43 43 43 00 00 00 00 00 00 00 00 ....CCCC........ 0x08049ab4 19 00 00 00 18 ef 14 40 18 ef 14 40 00 00 00 00 .......@...@.... 0x08049ac4 00 00 00 00 18 00 00 00 18 00 00 00 42 42 42 42 ............BBBB 0x08049ad4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0x08049ae4 19 00 00 00 43 43 43 43 00 00 00 00 00 00 00 00 ....CCCC........ 0x08049ab4 31 00 00 00 30 ef 14 40 30 ef 14 40 00 00 00 00 1...0..@0..@.... 0x08049ac4 00 00 00 00 18 00 00 00 18 00 00 00 42 42 42 42 ............BBBB 0x08049ad4 00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 00 ............0... 0x08049ae4 18 00 00 00 43 43 43 43 00 00 00 00 00 00 00 00 ....CCCC........ 다시 비슷한 덤프이다.(차근차근 안하면 중간에 헷갈려서 뭐가뭔지...^^) 이번에 우리가 눈여겨 보와야 하는것은 free의 메커니즘이다...즉, 병합과정을 공부해보려는것인데.. free(mol2)에 의해서 어떠한 일이 발생되었는가를 자세히 살펴보면, 우선 앞서 free된 size1의 크기가 변경되고, fd,bk도 변경된것을 볼 수 있다. 그 증감은 size2의 크기와 동일한것을 볼수 있는데...이처럼, 앞선 메모리가 free되어있경우 재 사용가능한 블럭수를 줄이고, 크기를 늘리기 위해서 합병이 된다. 이러한 방식의 free메커니즘은 free가 호출될때마다 시행되며 하나로 합쳐지게 된다.

원재아빠 블로그를 보면 mol1이 free되었고, 연속으로 mol2를 free 하려는 과정을 보여준다.

이때 mol2를 free하는 과정에서 이전 chunk가 free chunk 임을 확인하고, 이에 병합 과정을 보여준다.


이후 쉘코드를 획득하는 과정은 이해하기 쉬우니 위의 블로그를 참조하기 바람~!




'공부는 계속 .. > Pwnable Writeup' 카테고리의 다른 글

Plaid CTF 2014 ezhp  (0) 2018.03.01
Protostar heap3  (0) 2018.02.27
Codegate 2017 - babypwn  (0) 2018.02.22
Codegate 2014 Nuclear  (0) 2018.02.21
basic-rop  (1) 2018.02.20