8/3/2019 Exploring and Exploiting Malloc
1/75
Exploring and Exploiting
malloc
Breaking the Heap for Fun and
Profit
8/3/2019 Exploring and Exploiting Malloc
2/75
Lets store some data in C-
#include
int main()
{ int a = 5;
}
8/3/2019 Exploring and Exploiting Malloc
3/75
This allocates memory on the stack
Can only be allocated at compile time
8/3/2019 Exploring and Exploiting Malloc
4/75
What about allocating during run time?
Use malloc() for dynamic allocation
8/3/2019 Exploring and Exploiting Malloc
5/75
#include
int main()
{int *a = malloc(sizeof(int)); /*Size
can be given at runtime*/
}
8/3/2019 Exploring and Exploiting Malloc
6/75
What about buffer overflows?
Basically occur when data input exceedsthe memory available
DataOtherstuff
Input
Overflowed
8/3/2019 Exploring and Exploiting Malloc
7/75
Memory ahead gets CORRUPTED!!
Can lead from breaking programexecution to getting control over the OS
8/3/2019 Exploring and Exploiting Malloc
8/75
Buffer Overflows: Stack overflow:
#include
int main(){
char ch[50];
scanf(%s, ch);}
8/3/2019 Exploring and Exploiting Malloc
9/75
Stack overflow exploited since Stack isalso used to store IP during function calls
Overriding stack could lead to controllingIP, hence program execution
8/3/2019 Exploring and Exploiting Malloc
10/75
What about the Heap?
The heap is specialized to store onlydata. So how to exploit overflow?
8/3/2019 Exploring and Exploiting Malloc
11/75
To exploit the Heap, we need tounderstand malloc() and the memory
allocator
8/3/2019 Exploring and Exploiting Malloc
12/75
Malloc(), free() and realloc() are functionsof a dynamic memory allocator.
Many allocators are available. The mostcommon one is Doug Leas allocator (called
Dlmalloc).
8/3/2019 Exploring and Exploiting Malloc
13/75
So, how does the memory allocator
allocate memory?
Well, it already has memory, and can
always obtain more from the OS. Theproblem is managing this block of memoryinto individual variables, which can befreed and allocated at any time duringprogram execution
8/3/2019 Exploring and Exploiting Malloc
14/75
Basically, memory is allocated in terms ofchunks. The entire heap memory isdivided into chunks.
There are basically 2 kinds of chunks:
-> Allocated chunks
-> Free chunks
8/3/2019 Exploring and Exploiting Malloc
15/75
Allocated chunks look like this in memory-
8/3/2019 Exploring and Exploiting Malloc
16/75
And Free chunks like this-
8/3/2019 Exploring and Exploiting Malloc
17/75
There is only one rule governing chunks:No 2 free chunks can be neighboring.
Alongside with these chunks, there is aspecial chunk, the wilderness chunk.This is basically a special free chunk,
located at the top of the availablememory
8/3/2019 Exploring and Exploiting Malloc
18/75
So, our chunks could possibly look like this
Chunk 1:Allocated
Chunk 2:Free
Chunk 3:Allocated
Chunk 4:Allocated
Wilderness chunk(Free, but special)
Memory Addresses
8/3/2019 Exploring and Exploiting Malloc
19/75
While the allocated blocks are returnedback to the user, what about freechunks?
DLMalloc keeps a track of the freechunks using a binning system. Stores
Free chunks in 128 bins
8/3/2019 Exploring and Exploiting Malloc
20/75
There are 128 bins.In each bin, free chunks of particular sizeare stored. In the first 62 bins (called
small bins), chunks of exact size arestored
Bin 2: 16 bytefree chunks
only
Bin 3: 24 bytefree chunks
only
Bin 63: 508byte free
chunks only..
8/3/2019 Exploring and Exploiting Malloc
21/75
The remaining bins store chunks in aparticular range. The chunks are orderedin each bin in descending order
Bin 64: 512-575 bytes
Bin 65: 576 639 bytes
Bin 128: Upto231 bytes
..
8/3/2019 Exploring and Exploiting Malloc
22/75
Checkpoint:Introduction: Check
Overflows: Check
DLMalloc Intro: CheckChunks in Heap: Check
Binning System for Free Chunks: Check
8/3/2019 Exploring and Exploiting Malloc
23/75
Now that we saw the structure of theheap, lets see the main macros that areused, especially in the binning system.
Unlink() and FrontLink()
Consequently, these are the macros which
will help exploit overflows
8/3/2019 Exploring and Exploiting Malloc
24/75
Unlink() Macro:To remove a free chunk from a bins list.Quite simply put
#define unlink( P, BK, FD ) { \
BK = P->bk; \
FD = P->fd; \
FD->bk = BK; \
BK->fd = FD; \}
8/3/2019 Exploring and Exploiting Malloc
25/75
Frontlink() Macro:
Does just the opposite: Adds a free chunk
into a bin. *Not* so simply put-#define frontlink( A, P, S, IDX, BK, FD ) { \if ( S < MAX_SMALLBIN_SIZE ) { \
IDX = smallbin_index( S ); \mark_binblock( A, IDX ); \BK = bin_at( A, IDX ); \FD = BK->fd; \P->bk = BK; \P->fd = FD; \
FD->bk = BK->fd = P; \} else { \
IDX = bin_index( S ); \BK = bin_at( A, IDX ); \FD = BK->fd; \if ( FD == BK ) { \
mark_binblock(A, IDX); \} else { \
while ( FD != BK && S < chunksize(FD) ) { \
FD = FD->fd; \} \BK = FD->bk; \
} \P->bk = BK; \P->fd = FD; \FD->bk = BK->fd = P; \
} \}
8/3/2019 Exploring and Exploiting Malloc
26/75
We see a lot of pointer operations goingon the macro to exploit
But what calls these macros anyways?
8/3/2019 Exploring and Exploiting Malloc
27/75
Malloc() !!
Free() !!
realloc() !!
Lets see what malloc() and free() are.
realloc() can also be exploited in a similarway as malloc(), so not discussed
8/3/2019 Exploring and Exploiting Malloc
28/75
8/3/2019 Exploring and Exploiting Malloc
29/75
8/3/2019 Exploring and Exploiting Malloc
30/75
Step 2: The most recently remainderedchunk is used if large enough. If it is
large enough, it is split into 2 parts. Thefirst is allocated, the other becomes thenew MRR chunk. If it aint big enough
though, just put it in bin, and go Step 3
8/3/2019 Exploring and Exploiting Malloc
31/75
Step 3: Other bins are scanned inincreasing order for chunks. If large
enough chunk is found, remove from bin(using unlink) and split into parts. Thefirst part is allocated, the second
becomes the MRR chunk.If there is no large enough chunkanywhere in bins, go step 4
Free Chunk: 900bytes
Unlink()
Allocated: 600bytes
Free Chunk: MRRchunk 300 bytes
8/3/2019 Exploring and Exploiting Malloc
32/75
Step 4: Check if wilderness chunk is largeenough. If it is, then split into 2 parts.Allocate the lower part, while the upperpart becomes the new wilderness chunk
If wilderness chunk is also not large
enough, go to step 5
Wilderness chunkNew Wildernesschunk
Allocated Chunk
8/3/2019 Exploring and Exploiting Malloc
33/75
Step 5: Ask the OS for help. Use sbrkand mmap to expand memory available. If
this also fails, then just give up already!
8/3/2019 Exploring and Exploiting Malloc
34/75
Ok. So that was malloc() :
First check if perfect free chunk exists.
Then check MRR chunk. Then check binsfor large chunks to be splitted. Thencheck the wilderness chunk. If this alsofails, ask OS for help.
8/3/2019 Exploring and Exploiting Malloc
35/75
Free(): To perform the opposite ofmalloc(). It frees up an allocated chunk,
adding it to bins (and coalescing withneighboring chunks)
8/3/2019 Exploring and Exploiting Malloc
36/75
How does free() work?
Step 1: If chunk borders wildernesschunk, coalesce into a bigger wildernesschunk. Also, coalesce the previous
neighbor free chunk if exists
Wilderness chunk
Allocated Chunk
Free Chunk
New Wilderness Chunk
Unlink()
8/3/2019 Exploring and Exploiting Malloc
37/75
Step 2: Coalesce free chunk with its freechunk neighbors. Remove each free chunk
neighbor by unlink(), then consolidate.Finally, frontlink() the new big free chunk
Free Chunk
Allocated Chunk
Free Chunk
Coalesced Free Chunk
Unlink()
Unlink()
FrontLink()
8/3/2019 Exploring and Exploiting Malloc
38/75
Done.
Thus, weve just seen the basic steps usedin malloc() and free() .
8/3/2019 Exploring and Exploiting Malloc
39/75
Before we start digging into the exploit,we must explore a few details more
8/3/2019 Exploring and Exploiting Malloc
40/75
Just to recollect, allocated chunks looklike this in memory-
8/3/2019 Exploring and Exploiting Malloc
41/75
While free chunks look like this
8/3/2019 Exploring and Exploiting Malloc
42/75
The prev_size field of a chunk: This 4byte field is the first field in a chunk.
If the chunk previous to this one is free,then this field stores the size of thatfree field.
8/3/2019 Exploring and Exploiting Malloc
43/75
If the previous chunk is not free, though,then this field is overwritten by the userdata of the previous chunk (andconsidered during malloc() )
8/3/2019 Exploring and Exploiting Malloc
44/75
How to know if a chunk is free or not?
The chunk itself does not contain this
information.T
he next chunks size field,however, contains 2 flags, one of which isPREV_INUSE, which specifies if previouschunk is free or allocated
8/3/2019 Exploring and Exploiting Malloc
45/75
AndLastly, how function calls actually dotake place?
Due to concerns of relocating, a call tofunction func() is not replaced in assemblyby call
main(){func();
}
func(){
}
call
8/3/2019 Exploring and Exploiting Malloc
46/75
Instead, we have a Global Offset Table
which stores all function pointers. A callto a function would actually first go tothe GOT, get the function pointer fromthere, and then go to that function
pointer
main(){func();
}
func(){
}
call
Global Offset TableFunction ptr1Function ptr 2
8/3/2019 Exploring and Exploiting Malloc
47/75
Armed with this knowledge, lets exploitHeap overflows!!
Well discuss 2 methods:(a)Using the unlink() (easier)
(b)Using the frontlink() (not so easy)
8/3/2019 Exploring and Exploiting Malloc
48/75
Exploiting unlink():We see that unlink() is
Check out line 4. We see that we can
modify the value of memory locationspecified
(1) #define unlink( P, BK, FD ) { \
(2) BK = P->bk; \
(3) FD = P->fd; \(4) FD->bk = BK; \(5) BK->fd = FD; \
(6)}
8/3/2019 Exploring and Exploiting Malloc
49/75
Why would we want to modify the value ofa particular memory location?
We could modify the memory location inGOT, and set a function pointer to pointto our code. Thus, when that function is
called, our code is executed instead
8/3/2019 Exploring and Exploiting Malloc
50/75
We could specify FD as the location in
GOT, while BK would be the location ofour shell code (custom code to do nastystuff such as spawn a shell)
8/3/2019 Exploring and Exploiting Malloc
51/75
Ok. But how do you call unlink() with sucha free block with bad bk and fd?
1. We can overflow a buffer, causing thechunk to be designated injustly asfree, and call unlink at step 2 of free()
2.W
e can overflow a buffer, causing anexisting free block to have overwrittenbk and fd. In this case, this blockwould be inaccessible since it would be
effectively out of bin.
So method 1 it is!
8/3/2019 Exploring and Exploiting Malloc
52/75
Lets jump directly into the code!(1) #include
(2)
(3) int main(void)(4) {(5) char* overflow = malloc(768);
(6) char* p = malloc(64);(7) scanf("%s",overflow);
(8) free(overflow);
(9) free(p);
(10) return 0;
(11)}
When malloc(768) is called, the wildernesschunk is split to allocate memory. P wouldalso be a chunk split from wilderness chunk
overflow P Wilderness Chunk
(1) #include
8/3/2019 Exploring and Exploiting Malloc
53/75
We can overflow overflow, and can hencewrite into p. We can change the size fieldof this chunk, and modify so that p is
designated as a free chunk
(1) #include
(2)
(3) int main(void)
(4) {
(5) char* overflow = malloc(768);
(6) char* p = malloc(64);(7) scanf("%s",overflow);
(8) free(overflow);
(9) free(p);
(10) return 0;
(11)}
(1) #include
8/3/2019 Exploring and Exploiting Malloc
54/75
(1) #include
(2)
(3) int main(void)
(4) {
(5) char* overflow = malloc(768);
(6) char* p = malloc(64);(7) scanf("%s",overflow);
(8) free(overflow);
(9) free(p);
(10) return 0;
(11)}
Prev_sizesize
User Data
overflow
Prev_sizesize
User Data
P
Input
(overflowed)
(1) #include
8/3/2019 Exploring and Exploiting Malloc
55/75
Now, we must make p free chunk. Thus,next chunks size must be modified. We canmodify the location of next chunk by
modifying the size of p. We can put thenext chunk somewhere in user-data of p
(1) #include
(2)
(3) int main(void)
(4) {
(5) char* overflow = malloc(768);
(6) char* p = malloc(64);(7) scanf("%s",overflow);
(8) free(overflow);
(9) free(p);
(10) return 0;
(11)}
(1) #include
8/3/2019 Exploring and Exploiting Malloc
56/75
(1) #include
(2)
(3) int main(void)
(4) {
(5) char* overflow = malloc(768);
(6) char* p = malloc(64);(7) scanf("%s",overflow);
(8) free(overflow);
(9) free(p);
(10) return 0;
(11)}
Prev_size
Size : modified
User Data
P
Prev_size of next chunk
Size of next chunk
Indicates p is free
Prev_size
Size
fd
bk
Free Space
(1) #include
8/3/2019 Exploring and Exploiting Malloc
57/75
Since p is thought to be free, whenfree(overflow) is called, since p is free(), itwill be coalesced with overflow. Thus,
unlink would be called on p.We must thus, in the overflow itself, putproper values of fields of fd and bk
(1) #include
(2)
(3) int main(void)
(4) {
(5) char* overflow = malloc(768);
(6) char* p = malloc(64);(7) scanf("%s",overflow);
(8) free(overflow);
(9) free(p);
(10) return 0;
(11)}
(1) #include
8/3/2019 Exploring and Exploiting Malloc
58/75
(1) #include
(2)
(3) int main(void)
(4) {
(5) char* overflow = malloc(768);
(6) char* p = malloc(64);(7) scanf("%s",overflow);
(8) free(overflow);
(9) free(p);
(10) return 0;
(11)}
P
Prev_size
Size
fd
bk
Free Space
shellcode
Function pointer
Thus we see that the final shellcode takes
8/3/2019 Exploring and Exploiting Malloc
59/75
Thus, we see that the final shellcode takeson the form
8/3/2019 Exploring and Exploiting Malloc
60/75
Voila Instant shell with the above exploit.
Now for introduction 2nd method: Usingfrontlink()
Just to recollect the frontlink() macro is
8/3/2019 Exploring and Exploiting Malloc
61/75
Just to recollect, the frontlink() macro is#define frontlink( A, P, S, IDX, BK, FD ) { \
if ( S < MAX_SMALLBIN_SIZE ) { \
IDX = smallbin_index( S ); \
mark_binblock( A, IDX ); \
BK = bin_at( A, IDX ); \
FD = BK->fd; \
P->bk = BK; \
P->fd = FD; \
FD->bk = BK->fd = P; \
(1) } else { \
IDX = bin_index( S ); \
BK = bin_at( A, IDX ); \FD = BK->fd; \
if ( FD == BK ) { \mark_binblock(A, IDX); \
} else { \(2) while ( FD != BK && S < chunksize(FD) ) { \
(3) FD = FD->fd; \
} \
(4) BK = FD->bk; \} \
P->bk = BK; \
P->fd = FD; \
(5) FD->bk = BK->fd = P; \
} \
}
We see the important lines
8/3/2019 Exploring and Exploiting Malloc
62/75
We see the important lines(1) } else { \
IDX = bin_index( S ); \BK = bin_at( A, IDX ); \FD = BK->fd; \
if ( FD == BK ) { \mark_binblock(A, IDX); \} else { \
(2) while ( FD != BK && S < chunksize(FD) ) { \(3) FD = FD->fd; \
} \
(4) BK = FD->bk; \} \P->bk = BK; \P->fd = FD; \
(5) FD->bk = BK->fd = P; \} \
}
This else is executed only for bigger bins.
We see that in 2, the loops finds the largestfd that is smaller than S. In line 4, BK isassigned FD->bk . And in 5, we set fd fieldsof BK, ie: (FD->bk)->fd
(1) } else { \IDX bi i d ( S ) \
8/3/2019 Exploring and Exploiting Malloc
63/75
IDX = bin_index( S ); \BK = bin_at( A, IDX ); \FD = BK->fd; \if ( FD == BK ) { \
mark_binblock(A, IDX); \} else { \
(2) while ( FD != BK && S < chunksize(FD) ) { \(3) FD = FD->fd; \
} \
(4) BK = FD->bk; \} \P->bk = BK; \P->fd = FD; \
(5) FD->bk = BK->fd = P; \} \
}
Thus, if we can create a FD with an bk beinga function pointer location, then BK->fdwould allow us to overwrite the function
pointer with the location of custom code.
(1) } else { \IDX bin index( S ); \
8/3/2019 Exploring and Exploiting Malloc
64/75
IDX = bin_index( S ); \BK = bin_at( A, IDX ); \FD = BK->fd; \if ( FD == BK ) { \
mark_binblock(A, IDX); \} else { \
(2) while ( FD != BK && S < chunksize(FD) ) { \
(3) FD = FD->fd; \} \
(4) BK = FD->bk; \} \P->bk = BK; \P->fd = FD; \
(5) FD->bk = BK->fd = P; \} \
}
But we can only overwrite BK->fd with P. Whatif P is not susceptable to overflow?
No problem. If we can store data in chunkprevious to P, then prev_size would contain thatdata as well. Thus, the first 4 bytes of P can be
a jump statement to the actual shellcode
Digging directly into the code lets see a
8/3/2019 Exploring and Exploiting Malloc
65/75
Digging directly into the code, let s see aprogram that can be exploited usingfrontlink()#include
int main(void)
{char* first, second, third, fourth, fifth, sixth;
first = malloc(800);
second = malloc(640);third = malloc(200);
fourth = malloc(644);fifth = malloc(200);
sixth = malloc(16);
scanf("%800s",first);
free(fifth);
scanf("%s",fourth); //Overflowablefree(second); //Injected here
return 0;
}
8/3/2019 Exploring and Exploiting Malloc
66/75
Here, we first can overflow fourth afterfifth is free()d. Thus, we can overwrite
fifth, which is already present in the bin,and hence the value of bk in fifth
8/3/2019 Exploring and Exploiting Malloc
67/75
When second is free()d, the last step offree() executes, which involves puttingsecond in the bin. This involves
Frontlink(second), which would take place inthe same bin as fifth.
8/3/2019 Exploring and Exploiting Malloc
68/75
Since fifth->bk points to function pointer,the function pointer can be overwritten withaddress of second
8/3/2019 Exploring and Exploiting Malloc
69/75
We can add text to first. We fill in thelast 4 bytes of first with a jump to theshellcode present in the rest of first.These last 4 bytes will be present inprev_size of second, ie, pointed by the
function pointer
h ll h l d
8/3/2019 Exploring and Exploiting Malloc
70/75
In a nutshell, the exploit designs are
8/3/2019 Exploring and Exploiting Malloc
71/75
Voila! Instant shell code execution using
frontlink()
8/3/2019 Exploring and Exploiting Malloc
72/75
And so, we saw in the presentation, 2 waysto exploit overflows in the heap to allow
arbitrary code execution
8/3/2019 Exploring and Exploiting Malloc
73/75
The main references for this presentation:
Vudo Malloc Tricks. Kaempf, Michel
"MaXX". 2007, Phrack 57, p. 0x08. Heap Overflow Tutorial
Along with the description of Dlmalloc andits source
Also, the article Once upon a free provided
insights into the working of free() withunlinkMe blocks
8/3/2019 Exploring and Exploiting Malloc
74/75
Further reading:
Advanced Doug lea's malloc exploits
Malloc Maleficarum
The House of Mind
8/3/2019 Exploring and Exploiting Malloc
75/75
By,
Gaurav Mogre
06co36