Post

Tcache Exploitation

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:

  1. An array of bins for different chunks sizes.
  2. 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:

  1. A pointer that points to the next free chunk in the bin.
  2. 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.
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:

  1. Free at least 2 chunks (tcache size).
  2. 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 the tcache bin with a target address that you want to overwrite (e.g. GOT entry or __malloc_hook).
  3. Make two malloc calls for chunk of the same size as the poisoned free chunk.
    • First malloc call returns, corrupted chunk from the tcache.
    • Second malloc call follows the poisoned next pointer from the tcache_entry structure and returns a chunk at the attacker’s chosen arbitrary address.
  4. You can now write data directly to the arbitrary address.

Reference

This post is licensed under CC BY 4.0 by the author.