Introduction to Heap

  • Heap is extremely dependent on the implementation, OS, specific implementation details
  • Is a modern exploitation technique
  • Need to understand the structure of the heap and how it works
  • Heap exploitation is basically mixing data and control
  • Harder to identify
    • called malloc in certian order, or called free twice etc.
  • Attacking the implentation of the heap, not programmers

What is the Heap?

  • OS provides memory (through malloc API) in multiples of 0x1000
  • Different libraries, OS etc. use different heap management implementations
  • Heap exploitation is hard
    • You can’t just ‘guess and check’.
    • need to understand the program to solve any heap challenge

Malloc Implentations

There are several different malloc implementations

  • dlmalloc: general purpose, no threads, very old
  • ptmalloc2 (glibc): fast for single-threaded applications, and fast for very small allocations. Also supports multithreading
  • Chrome and Firefox have their own malloc implentations (tcmalloc, jemalloc) for more specialised
    • There is a malloc_hook function (ptr) that allows you to specify your own memory allocator

How does Malloc Work?

  • Dynamic memory allocator
  • Allocates a large chunk of memory (through a syscall), and then
    • returns struct malloc_chunk
  • ‘First Fit’ allocator (usually)
    • What’s to return the first chunk that will fulfill the request
    • Each chunk stores metadata on either side of it (see struct malloc_chunk contents)
  • Maintains a ‘free’ list so it can quickly jump through free blocks
  • Some fields of the struct are only used if the chunk is free
  • size includes the metadata
  • fd is what is returned to the malloc user (and the following addresses are in bk). But if the block is free, it is a pointer to the next chunk.
  • On the first allocation, a large chunk is allocated. The first n bytes are the requested bytes from malloc, and the remaining region is the top chunk. We then break off the top of the top chunk each time we need more.
  • Global variable in libc called main_arena describes the heap

How does Free work?

  • Free needs to be fast. (Fast Code = low security)
  • The free chunks are divided into different sizes
    • and within the size classes, the chunks are sorted into bins (bucket sort)
    • So essentially an O(1) to return a chunk of a certain size
    • Bins are arrays of linked lists of chunks
    • The nodes in the linked lists are old chunks
  • Fast Bins are multiples of 8.
    • Array of linked lists of chunks of certian sizes
    • Always take first off the list - so O(1) retrieval
    • Never merge bins
  • Small Bins
    • Faster than large bins
    • Each bin maintains a doubly linked list (FIFO)
    • Each bin has chunks of same size.
    • There are more small bins
    • When you free two chunks adjacent to each other: then the chunks are coalesced into one larger chunk
  • Unsorted Bin
    • Initially a free chunk is put into an unsorted bin
    • When a new chunk is allocated, it loops through this list and sorts the chunks until the correct size is found.
  • tcache
    • Very simliar to fast bins, except they removed all the security checks
    • The only check it does is to ensure that there aren’t already max chunks in the tcache.

Reference: Azeria Labs

Exploits

It’s hard to exploit a program with only one of these vulnerabilities. You usually need a few to perform exploitation.

  • Use after free
    • You can overwrite the forward pointer, and corrupt the free list struture
    • Can also provide leaks
  • Double free
    • In fastbins, it will check that the free request is not the first item in the free list already (tcache doesn’t). To get double free, need to have something in between the frees so that the check passes
  • Leaking with small chunks
    • The small bins point back into the main arena (in libc).
      • (The first element’s backward pointer points into libc)
    • If you can print the first thing in smallbin list, you have an address leak into libc!
  • Forging chunks
    • Corrupt the free structure to forge a chunk wherever you like in memory
  • Heap Spray

Usually the goal is to get two chunks to overlap and overwrite data in another chunk.

ROP is hard on with heap (because you can’t control the stack), so one_gadget is the saviour.

pwndbg Commands

Command Purpose
heap Shows all chunks allocated, and their types
bins Shows type of bins
vis_heap_chunks Visualise the heap chunks

Need to make sure using the same libc library

  • LD_PRELOAD allows you to force a program to use a different libc version
  • Need to do this in case the algorithms are different in different versions.

Suggested Reading