Dynamic Allocator Misuse (Module B)
Last updated on
Note: Most of the below information is summarized from Dr. Yan Shoshitaishvili’s pwn.college lectures from the “Memory Errors” module. Much credit goes to Yan’s expertise! Please check out the pwn.college resources and challenges in the sources
Dynamic Allocator Misuse (Module B)
Table of Contents
The Heap
Types of Memory
- ELF .text: Where the code lives
- ELF .plt: Where the library function stubs live
- ELF .got: Where pointers to imported symbols live
- ELF .bss: Used for uninitialized global writable data
- Example: global arrays without initial values
- ELF .data: Use for pre-initialized global writable data
- Example: global arrays with initial values
- ELF .rodata: Yse for global read-only data
- Example: string constants
- Stack: Local variables, temporary storage, call stack metadata
- Heap: Place to store long-lived dynamic memory
- Example: variable-length list
How the Heap Works
- The heap works by initially allocating a large chunk of memory space, but only supplying smaller parts of that space to a program as needed
- It is implimented by ptmalloc/glibc (and analogues) and uses the following main functions (not an exhaustive list):
malloc()
: allocate some memoryfree()
: free a prior allocated chunkrealloc()
: change the size of an allocationcalloc()
: allocate and zero-out memory
The Data Segment
- Historical oddity from segmented memory spaces
- With ASLR, placed randomly into memory near the PIE base
- Starts with a size of 0
- managed by the
brk
andsbrk
system callssbrk(NULL)
: returns the end of the data segmentsbrek(delta)
: expands the end of the data segment bydelta
bytesbrk(addr)
: expands the end of the data segment toaddr
- This process is managed just like
mmap()
- ptmalloc slices off bits of the data segment for small allocations, and uses
mmap()
for large allocations
Dangers of the Heap
Why is the heap vulnerable:
- Used by imperfect human programmers
forget to free memoryleads to resource exhaustion
forget all the spots where pointers to data are stored
forget what’s been freedusing free memory
freeing free memory
corrupting metadata used by the allocator to keep track of heap stateconceptually similar to corruption internal function state on the stack - A library that strived for performance
allocation and deallocation needs to be fast, or programs will slow down
optimizations often leave security as an afterthought
Double Freeing
- Pointers to an allocation remain valid after
free()
ing the allocation, and are sometimesfree()
d again - New versions of glibc/ptmallloc introduced the
key
check- If
key
is overwritten, then the heap can be abused
- If
Thread Local Caching (tcache)
- tcache in ptmalloc is used to speed up repeated (small) allocations in a single thread
- A caching layer with very few security checks
- Implemented as a singly-linked list, with each thread having a list header for different-sized allocations
What Happens on free()
- Select the right “bin” based on the size
- Check to make sure the entry hasn’t already been freed (double-free)
- Push the freed allocation to the front of the list
- Record the tcache_perthread_struct associated with the freed allocation (for checking against double-frees)
What Happens on Allocation
- Select the bin number based on the requested size
- Check the appropriate cache for available entries
- Reuse the allocation in the front of the list if available
Things NOT done:
- clearing all sensitive pointers (only
key
is cleared) - checking if the
next (return[0])
address makes sense
Metadata and Chunks
- ptmalloc uses lots of metadata to track its operation and is kept in:
- Global metadata (the tcache structure)
- Per-chunk metadata
- A “chunk” is what
malloc()
is actually tracking, and the address seen by programmers is just the usable memory AFTER the headers in the chunk
- A “chunk” is what