Notes
ROP
Stack pivoting
One gadget
Heap
mallocnever clears the user data unless calloc is used- glibc-2.32 onwards have safe-linking.
safe-linking
fdpointers in tcache and fastbins are mangled to make exploitation harder.- straight-forward principle: use randomness from ASLR to mangle ptrs.
- heap leak is needed to break safe-linking.
- target address should be 0x10 byte aligned
def mangle(pos, ptr):
"""
pos: int = position of heap chunk
ptr: int = ptr we need. This should be 0x10 byte aligned
"""
return (pos >> 12) ^ ptr
tcache
- The free bin is a single linked list (LIFO based).
- Used to store small freed allocations .
- 7 allocations per bin.
ptr = malloc(size); free(ptr)with size <= 0x408 will go in tcache.- “thread” cache. So one tcache per thread.
NOTE-1: >= glibc-2.32 requires heap leak for breaking safe-linking.
NOTE-2: malloc clears out key field (address+8) for tcache
tcache bin struct:
typedef struct tcache_perthread_struct {
char counts[TCACHE_MAX_BINS];
tcache_entry* entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;
tcache entry struct:
typedef struct tcache_entry {
struct tcache_entry* next;
uintptr_t *key;
} tcache_entry;
key field prevents double-free.
https://elixir.bootlin.com/glibc/glibc-2.35/source/malloc/malloc.c#L312
Arbitrary Access Read/Write (AAW / AAR)
- UAF write is required.
- heap leak to break safe-linking
a = malloc(0x10);
b = malloc(0x10);
free(a);
free(b);
// tcache freelist: [b -> a -> NULL]
// write to b, to overwrite next ptr
// take care of safelinking if needed
b = malloc(0x10); // freelist [ mangled_target -> NULL]
target = malloc(0x10); // get target
// write/read from target ...
Double-free protection bypass
- UAF write is required.
a = malloc(0x10);
free(a);
write(a, "abcdefghijklmnop", 0x10); // overwrite the key(+8) field
free(a); // double free
House of spirit
The main principle: free(ptr) doesn’t check if the ptr points to valid heap memory, so if we can craft a fake “malloc” like chunk (with chunk size <= 0x410 and malloc arg <= 0x408) then freeing this ptr will add the address pointed by chunk on tcache.
Requirments:
- Free on near arbitrary ptr (ptr needs to be 0x10 byte aligned).
pseudocode rough sketch:
uint64_t fake_chunks[10];
fake_chunks[1] = 0x40; // chunk size
a = &fake_chunks[2];
free(a);
void* b = malloc(0x35); // get chunk of size 0x40
// b == &fake_chunks[2] (user controlled address)