Overview
The House of Spirit attack on tcache allows an attacker to free a fake chunk and subsequently havemalloc() return a pointer to that fake chunk. This tcache variant is significantly simpler than the original House of Spirit attack because tcache has fewer security checks.
The name “House of Spirit” comes from the original Malloc Maleficarum paper. The tcache version is much easier to exploit because
_int_free calls tcache_put without checking if the next chunk’s size and prev_inuse fields are valid.Glibc Version Compatibility
Works on: glibc 2.26 and later (any version with tcache) Key advantage: Unlike the original House of Spirit, you don’t need to create a fake chunk after the fake chunk being freed. The tcache path in_int_free bypasses many sanity checks.
What This Technique Achieves
1
Create a fake chunk
Craft a fake chunk structure in a controlled memory region (stack, data segment, etc.)
2
Free the fake chunk
Call free() on a pointer to the fake chunk’s data region
3
Get arbitrary pointer
Next malloc() of the same size returns a pointer to the fake chunk region
Key Differences from Original House of Spirit
Tcache version is simpler:
- No need to create a fake “next chunk” with valid size/prev_inuse fields
- No wilderness/top chunk proximity checks
- The
PREV_INUSEbit is ignored for tcache chunks - Fewer size validation checks
- Chunk size must fall into tcache category (
size <= 0x410, malloc arg<= 0x408on x64) - The
IS_MMAPPED(2nd LSB) andNON_MAIN_ARENA(3rd LSB) bits must be 0 - Memory address must be 16-byte aligned
Source Code
Step-by-Step Walkthrough
1. Initialize Heap
2. Create Fake Chunk Structure
__attribute__((aligned(0x10))) ensures this.
3. Set Up Fake Chunk Size
- Must be in tcache range:
0x20 <= size <= 0x410on x64 - Bits that must be 0:
IS_MMAPPEDandNON_MAIN_ARENA PREV_INUSEbit is ignored (can be 0 or 1)- Must match the size of your subsequent malloc call (rounded up)
4. Overwrite Pointer to Fake Chunk
fake_chunks[2] (the user data), not fake_chunks[1] (the size field). This is because malloc returns a pointer to the data region, which is 16 bytes after the chunk header.
5. Free the Fake Chunk (Vulnerability Point)
free()calculates the chunk header location:&fake_chunks[2] - 0x10 = &fake_chunks[0]- Reads the size from
fake_chunks[1]:0x40 - Calls
tcache_put()with minimal checks - The fake chunk is now in the tcache bin for size 0x40
6. Allocate from Tcache
Fake Chunk Memory Layout
Prerequisites
1
Arbitrary free
Ability to call free() with a controlled pointer value
2
Memory control
Ability to write to a memory region (stack, .bss, etc.) to create the fake chunk
3
Size knowledge
Know what size malloc() will be called with to match your fake chunk size
Common Use Cases
1. Stack-based exploitation:Detection and Mitigation
Why this works:- Tcache was designed for speed, not security
tcache_put()has minimal validation- No checks for whether the chunk came from the heap
- Validate that freed chunks are within heap bounds
- Add magic values to chunk headers
- Implement address space layout randomization (ASLR)
Try It Yourself
Practice on Ret2 Wargames
Debug this technique in an interactive browser environment
Related Techniques
- [Original House of Spirit/techniques/house/house-of-spirit) - The fastbin version with more checks
- Tcache Poisoning - Corrupt fd pointers in tcache
- [House of Force/techniques/house/house-of-force) - Corrupt top chunk instead
