Link to this headingDlmalloc

  • The original Linux glibc implementation until 2006
  • Leaking Pointers allow an attacker to de reference pointers to get pointers into glibc and the heap

Link to this headingFunctions

malloc - Allocates a chunk* at least size bytes and returns

  1. If size is less than or equal to a fast bin or a small bin use it.
  2. Move fast bins to unsorted bins
  3. Merge adjacent freed chunks together
  4. Sort bin
  5. Search through best fit bins
  6. Split the Top

free - De-allocates chunk* pointed by p

  1. If chunk is a fast chunk then put it in the fast bin
  2. Else
    • Merge adjacent freed chunks together
    • Then put it into the Unsorted bin

realloc - Increases the size of a chunk* while preserving it’s content

calloc - malloc but clears data

Link to this headingStructures

  • Chunks must be at least 0x20 bytes
  • Since Chunks are 8 byte aligned the 3 Least significant bits are used for Flags
    • Bit 0: previous chunk in-use (prev_inuse)
      • If the prev_inuse is not set then malloc will use prev_size
    • Bit 1: Was the chunk allocates with mmap. (is_mmapped)
    • Bit 2: is allocated from a spawned thread? non_main_arena

Allocated Chunk:

          malloc returned address
                   ||
                   \/
            ----------------------------
            | size | user-data ....... |
            ----------------------------

Freed Malloc Chunk:

          malloc returned address
                   ||
                   \/
-------------------------------------------------------------------------------------------------------
| prev_size | size |  next_chunk_pointer | prev_chunk_pointer | fd_nextsize | bk_nextsize | ... | size |
-------------------------------------------------------------------------------------------------------

Link to this headingBins

TypeSizeList TypeInfo
Fast[0x20 - 0x80]Single Linkedprev_inuse is set
UnsortedAll SizesDouble Linkedchunks before sorted
Small[0x20 - 0x400)Double Linked
LargeRangesTwo Level Double Linked

Link to this headingArena

Main Arena:

  • Is a global variable in the program
  • Contains the pointers to the bins
  • top points to “wilderness”

Arena/malloc_state:

--------------------------------------------------------------------------
| mutex | flags | fastbins[] | top | remainder |       bins[]        |...|
--------------------------------------------------------------------------
                                              /                       \
                                              +------------------------+
                                              |unsorted|small[]|large[]|
                                              +------------------------+

Thread Arena:

  • Works on Glibc version < 2.26
    • Because the freed memory thinks that the previous block is also freed memory it combinds the data together to a bigger chunk.
    • With this confusion of data this allows the unlink macro to be run.
    • This results in arbitrary write
  1. Use a buffer to overwrite the heap meta data for an object that has a size greater than 0x70 bytes.
    • We set up the prev_chunk_pointer to the pointer to the global buffer address - 0x10.
      • This makes it so that when dereferenced the prev_chunk_pointer points to the global buffer address. ((buffer->prev_chunk_pointer)->next_chunk_pointer == buffer)
    • We set up the next_chunk_pointer to the pointer to the global buffer address - 0x18.
      • This makes it so that when dereferenced the next_chunk_pointer points to the global buffer address. ((buffer->next_chunk_pointer)->prev_chunk_pointer == buffer)
    • We set the prev_size (originally 0x90 because of metadata) to a smaller value that falls within the . Usually the size without the metadata (0x80).
    • Using the buffer address we overwrite the previous_in_use flag to false
  2. Then call free on the object.
    • This will set the buffer + 0x18 to a pointer that points to the start of the buffer.
  3. This can be exploited by changing the pointer in buffer + 0x18 and then writing to the buffer.
    • This will dereference the pointer in buffer + 0x18 and write data to that address

Link to this headingFixes

  • Two new security checks include corrupted size vs. prev_size and corrupted double-linked list

Link to this headingExample

Link to this headingFastbin Consolidation Double Free

  • Works on Glibc version < 2.30
    • [Double Free](/Exploitation/Heap/Double Free.md) check is bypassed when a large chunk is allocated between the two frees.
    • This makes the same address be in the fastbin and the unsorted bin.
    • When making new allocations

Vulnerable Example:

#include <stdio.h> #include <stdint.h> #include <stdlib.h> int main() { void* p1 = malloc(0x40); void* p2 = malloc(0x40); fprintf(stderr, "Allocated two fastbins: p1=%p p2=%p\n", p1, p2); fprintf(stderr, "Now free p1!\n"); free(p1); void* p3 = malloc(0x400); fprintf(stderr, "Allocated large bin to trigger malloc_consolidate(): p3=%p\n", p3); fprintf(stderr, "In malloc_consolidate(), p1 is moved to the unsorted bin.\n"); free(p1); fprintf(stderr, "Trigger the double free vulnerability!\n"); fprintf(stderr, "We can pass the check in malloc() since p1 is not fast top.\n"); fprintf(stderr, "Now p1 is in unsorted bin and fast bin. So we'will get it twice: %p %p\n", malloc(0x40), malloc(0x40)); }

Link to this headingHouse of Spirit

  • Make a fake chunk and change the pointer to be freed.
  • This allows the same control as the Unsafe Unlink.
    • index 0 is the Pointer to write data to
    • index 3 is the data that write to that address