Skip to main content

Overview

Tcache metadata poisoning is an exploitation technique that directly manipulates the tcache_perthread_struct, which is the metadata structure controlling the tcache. By corrupting this structure, an attacker can:
  1. Insert arbitrary pointers into tcache bins
  2. Control the count of chunks in each bin
  3. Make malloc return completely arbitrary addresses without traditional heap corruption
The tcache metadata is stored at the beginning of the heap, immediately after the initial heap chunk. It contains two arrays: counts[] tracking how many chunks are in each bin, and entries[] containing the head pointers for each bin’s freelist.

Glibc Version Compatibility

Works on: glibc 2.26 and later (any version with tcache) Key insight: The tcache metadata is just a regular heap chunk. If you can corrupt it, you have complete control over what malloc returns.

What This Technique Achieves

1

Locate tcache metadata

Calculate the address of the tcache_perthread_struct
2

Corrupt metadata

Write arbitrary pointer to entries[N] and set counts[N] = 1
3

Allocate from corrupted bin

malloc() with size corresponding to bin N returns your arbitrary pointer
This is arguably the most powerful tcache attack because you bypass all traditional heap corruption and directly control allocation behavior.

Tcache Metadata Structure

Memory layout:
Total size: 0x280 bytes (64 * 2 + 64 * 8)

Source Code

Step-by-Step Walkthrough

1. Initialize Heap and Locate Metadata

The first malloc initializes the heap structure:

2. Calculate Metadata Address

Calculation:
  • victim is at heap_base + 0x2a0
  • metadata_size = 0x280
  • HEADER_SIZE = 0x10
  • metadata = victim - 0x10 - 0x280 = heap_base + 0x10
This points to the start of the tcache_perthread_struct data.
Why this works: The tcache metadata is always the first allocated chunk on the heap. If you have any heap pointer, you can calculate back to find the metadata.

3. Corrupt Metadata (Vulnerability Point)

This is where the vulnerability is exploited. An attacker with a write primitive can corrupt the tcache metadata to inject arbitrary pointers.
Tcache bin index calculation:
  • Bin 0: chunk size 0x20 (malloc arg 0x01-0x18)
  • Bin 1: chunk size 0x30 (malloc arg 0x19-0x28)
  • Bin 2: chunk size 0x40 (malloc arg 0x29-0x38)
  • …
  • Bin N: chunk size (N+2) * 0x10
We choose bin 1, which corresponds to malloc(0x20). What we’re writing:

4. Trigger Arbitrary Allocation

When malloc(0x20) is called:
  1. Calculate tcache bin index: size 0x30 → bin 1
  2. Check counts[1]: it’s 1, so tcache has a chunk
  3. Get pointer from entries[1]: returns &stack_target
  4. Decrement counts[1] to 0
  5. Return &stack_target to user
Result: evil == &stack_target We’ve successfully made malloc return a completely arbitrary address!

Attack Variations

Variation 1: Multiple Arbitrary Allocations

Variation 2: Chain Multiple Chunks

In glibc 2.32+, the fd pointers are protected by safe-linking, so you’d need to properly mangle them:

Prerequisites

1

Heap pointer leak

Need at least one heap pointer to calculate metadata location
2

Write primitive

Ability to write to the tcache metadata structure (overflow, UAF, etc.)
3

Target address

Know the address you want malloc to return

Why This Is Powerful

Advantages over other techniques:
  1. No heap spray needed: Directly control what malloc returns
  2. Bypasses safe-linking: No need to corrupt fd pointers in chunks
  3. No double-free needed: Don’t need to free anything
  4. Works on any tcache size: Can target any of the 64 tcache bins
  5. Multiple targets: Can inject pointers into multiple bins at once
Comparison to tcache poisoning:

Common Use Cases

1. Stack pivoting:
2. Overwriting GOT entries:
3. Defeating PIE:

Detection and Mitigation

Why this works:
  • Tcache metadata is stored in a regular heap chunk
  • No special protections beyond normal heap protections
  • Malloc trusts the metadata completely
Potential mitigations:
  • Place tcache metadata in a separate, protected memory region
  • Add integrity checks (checksums, canaries) to metadata
  • Validate entries point to valid heap regions
  • Implement bounds checking on entries array access
Newer glibc protections:
  • Safe-linking (2.32+) makes it harder to create fake freelists, but doesn’t protect the metadata itself
  • Still vulnerable if you can corrupt the metadata structure
  • Tcache Poisoning - Corrupt individual chunk fd pointers
  • Tcache House of Spirit - Free fake chunks into tcache
  • [House of IO/techniques/house/house-of-io) - Another technique exploiting tcache metadata via UAF

Real-World Applicability

When you can use this:
  • Heap overflow that reaches the beginning of the heap
  • Use-after-free on an early allocation
  • Arbitrary write primitive (write-what-where)
  • Integer overflow leading to out-of-bounds write
Detection difficulty: Medium to High
  • Corrupted metadata might not be immediately obvious
  • Normal heap integrity checks won’t catch this
  • Requires heap forensics or metadata validation