Tcache Exploitation
Understanding Tcache
Thread Local Caching (Tcache
) is a set of bins, organised as singly-linked lists, that are local to each thread. Tcache
was made to avoid the need to lock a global arena for frequent small allocations (from 0x10 up to 0x400, excluding metadata), making multi-threaded programs faster. When a chunk is freed, it gets placed into one of these bins. Each bin can store up to 7 bins in a single thread, and when the tcache
bins are full then the chunks go to the standard bins. The tcache
bins are singly-linked lists (LIFO).
Each Thread has its own tcache_perthread_struct
which contains 2 arrays:
- An array of bins for different chunks sizes.
- A corresponding array of counts for each bin.
1
2
3
4
typedef struct tcache_perthread_struct {
char counts[TCACHE_MAX_BINS];
tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;
When a chunk is freed into the tcache
bin, its user data area is repurposed to store a tcache_entry
structure. The tcache_entry
structure contains:
- A pointer that points to the next free chunk in the bin.
- A key field used for security checks.
- This field is a pointer back to the
tcache_perthread_struct
structure, and its only purpose is to detect double free attempts. - This mitigation can be bypassed by overwriting the key field.
- This field is a pointer back to the
1
2
3
4
5
typedef struct tcache_entry {
struct tcache_entry *next;
/* This field exists to detect double frees. */
uintptr_t key;_
} tcache_entry;
Exploitation
You need some type of bug that can provide the initial foothold needed to carry out poisoning
:
- Use-After-Free (
UAF
) - Double Free
- Heap Overflow
Tcache
also has some mitigations:
- Double Free protection: (mentioned earlier) The key field in the
tcache_entry
field is used to detect double frees. - Safe Linking : this mitigation encrypts the next pointer in the
tcache_entry
structure by XORing it with the address of the pointer itself, shifted right by 12 bits. This makes it harder to overwrite the pointer with an arbitrary address. This can be bypassed by leaking a heap address from the same memory region, they can often compute the correct value needed to poison the pointer.
Tcache
Poisoning
The aim of this technique is to trick malloc
into returning a pointer to an arbitrary memory location (e.g function return address, hook pointer, etc.). This technique provides a write-what-where primitive.
Process of the technique:
- Free at least 2 chunks (
tcache
size). - Use a vulnerability such as use-after-free or heap overflow, to overwrite the next pointer of the
tcache_entry
structure of a freed chunk that is currently in thetcache
bin with a target address that you want to overwrite (e.g. GOT entry or__malloc_hook
). - Make two
malloc
calls for chunk of the same size as the poisoned free chunk.- First
malloc
call returns, corrupted chunk from thetcache
. - Second
malloc
call follows the poisoned next pointer from thetcache_entry
structure and returns a chunk at the attacker’s chosen arbitrary address.
- First
- You can now write data directly to the arbitrary address.
Reference