House of Orange Exploitation
A heap exploitation technique that abuses malloc_printerr in glibc versions before 2.26 to achieve arbitrary code execution through fake _IO_FILE structure forgery.
When to Use This Skill
Use this skill when:
- You have a heap overflow vulnerability in a program linked against glibc < 2.26
- You need to exploit a heap corruption bug without calling
free - You want to abuse
malloc_printerrfor code execution - You need to forge
_IO_FILEstructures for libc exploitation - You're working on CTF challenges involving heap exploitation
Requirements
Before attempting this attack, verify:
- glibc version < 2.26 (the vulnerability was patched in 2.26)
- Heap overflow that can overwrite the top chunk size
- Libc leak to get base address
- Heap leak to get heap base address
- No ASLR or ability to bypass it
Background
In older glibc versions, malloc_printerr iterates through _IO_FILE structs stored in _IO_list_all and executes instruction pointers in those structs. This attack forges a fake _IO_FILE struct, writes it to _IO_list_all, and causes malloc_printerr to execute arbitrary code.
Attack Flow
Step 1: Set Up the Top Chunk
- Allocate a chunk to create the top chunk
- Overflow the allocated chunk to modify the top chunk size
- Ensure top chunk + size is page-aligned
- Ensure the prev_inuse bit of the top chunk is set
Step 2: Force Top Chunk into Unsorted Bin
- Allocate a chunk larger than the new top chunk size (but smaller than
mmap_threshold, default 128K) - This moves the old top chunk into the unsorted bin
- Note:
freeis never called in this attack
Step 3: Leak Libc Addresses
- Read data from the old top chunk in the unsorted bin
- Extract libc addresses from the chunk metadata
- Calculate the address of
_IO_list_all
Step 4: Perform Unsorted Bin Attack
- Use the overflow to write
topChunk->bk->fwd = _IO_list_all - 0x10 - When a new chunk is allocated, the old top chunk is split
- A pointer to the unsorted bin is written into
_IO_list_all
Step 5: Shrink the Old Top Chunk
- Adjust the size of the old top chunk to 0x61
- This serves two purposes:
- Insertion into Small Bin 4: The chunk ends up at the head of small bin 4, which is the location of the FD pointer of
_IO_list_all - Triggering Malloc Check: The size manipulation causes
mallocto perform internal checks, triggeringmalloc_printerrwhen it sees a zero forward chunk
- Insertion into Small Bin 4: The chunk ends up at the head of small bin 4, which is the location of the FD pointer of
Step 6: Set Up Fake _IO_FILE Structure
- Forge a fake
_IO_FILEstructure that overlaps with the old top chunk - Set key fields to pass libc internal checks:
_IO_write_baseand_IO_write_ptrmust be set correctly- Create a jump table with instruction pointer pointing to
systemor similar
- Include a pointer to a command (e.g., "/bin/sh")
Step 7: Trigger Code Execution
- Allocate a chunk to trigger the attack
- The manipulated
_IO_FILEstructure causes arbitrary code execution - Typically results in shell spawn or payload execution
Helper Scripts
Use the bundled scripts to assist with the attack:
Generate Fake _IO_FILE Structure
python scripts/generate_fake_io_file.py --help
This script generates a properly formatted fake _IO_FILE structure with the correct field values for the attack.
Calculate Offsets
python scripts/calc_offsets.py --help
This script calculates the necessary offsets for _IO_list_all, _IO_FILE fields, and other libc structures.
Example Exploit Structure
from pwn import *
# Connect to target
p = process('./vulnerable_program')
# Step 1: Leak libc and heap addresses
# ... (implementation depends on vulnerability)
# Step 2: Calculate addresses
io_list_all = libc.address + libc.symbols['_IO_list_all']
system = libc.address + libc.symbols['system']
bin_sh = next(libc.search(b'/bin/sh\x00'))
# Step 3: Generate fake _IO_FILE structure
fake_io_file = generate_fake_io_file(system, bin_sh)
# Step 4: Perform the attack
# ... (heap overflow to set up conditions)
# Step 5: Trigger execution
# ... (final malloc call)
p.interactive()
Common Pitfalls
- glibc version: Verify the target uses glibc < 2.26
- Page alignment: Ensure top chunk + size is page-aligned
- prev_inuse bit: Must be set on the top chunk
- _IO_FILE field values: Must pass libc internal checks
- mmap_threshold: Keep allocations under 128K to avoid mmap
References
- CTF Wiki - House of Orange
- GuyInATuxedo - House of Orange
- how2heap - House of Orange Example
- glibc Patch
Test Cases
To verify this skill works correctly, try these prompts:
- "I have a heap overflow in a program with glibc 2.23. How do I use House of Orange to get a shell?"
- "Generate a fake _IO_FILE structure for House of Orange exploitation targeting system('/bin/sh')"
- "Explain the House of Orange attack step by step for a CTF writeup"
- "Calculate the offsets needed for House of Orange on glibc 2.23 with libc base 0x7ffff7c00000"