Double Free - HackTricks

# Double Free

> [!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
> Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

> Support HackTricks
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.

## Basic Information

If you free a block of memory more than once, it can mess up the allocator's data and open the door to attacks. Here's how it happens: when you free a block of memory, it goes back into a list of free chunks (e.g. the "fast bin"). If you free the same block twice in a row, the allocator detects this and throws an error. But if you free another chunk in between, the double-free check is bypassed, causing corruption.

Now, when you ask for new memory (using `malloc`), the allocator might give you a block that's been freed twice. This can lead to two different pointers pointing to the same memory location. If an attacker controls one of those pointers, they can change the contents of that memory, which can cause security issues or even allow them to execute code.

Example:

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

    int main() {
        // Allocate memory for three chunks
        char *a = (char *)malloc(10);
        char *b = (char *)malloc(10);
        char *c = (char *)malloc(10);
        char *d = (char *)malloc(10);
        char *e = (char *)malloc(10);
        char *f = (char *)malloc(10);
        char *g = (char *)malloc(10);
        char *h = (char *)malloc(10);
        char *i = (char *)malloc(10);

        // Print initial memory addresses
        printf("Initial allocations:\n");
        printf("a: %p\n", (void *)a);
        printf("b: %p\n", (void *)b);
        printf("c: %p\n", (void *)c);
        printf("d: %p\n", (void *)d);
        printf("e: %p\n", (void *)e);
        printf("f: %p\n", (void *)f);
        printf("g: %p\n", (void *)g);
        printf("h: %p\n", (void *)h);
        printf("i: %p\n", (void *)i);

        // Fill tcache
        free(a);
        free(b);
        free(c);
        free(d);
        free(e);
        free(f);
        free(g);

        // Introduce double-free vulnerability in fast bin
        free(h);
        free(i);
        free(h);

        // Reallocate memory and print the addresses
        char *a1 = (char *)malloc(10);
        char *b1 = (char *)malloc(10);
        char *c1 = (char *)malloc(10);
        char *d1 = (char *)malloc(10);
        char *e1 = (char *)malloc(10);
        char *f1 = (char *)malloc(10);
        char *g1 = (char *)malloc(10);
        char *h1 = (char *)malloc(10);
        char *i1 = (char *)malloc(10);
        char *i2 = (char *)malloc(10);

        // Print initial memory addresses
        printf("After reallocations:\n");
        printf("a1: %p\n", (void *)a1);
        printf("b1: %p\n", (void *)b1);
        printf("c1: %p\n", (void *)c1);
        printf("d1: %p\n", (void *)d1);
        printf("e1: %p\n", (void *)e1);
        printf("f1: %p\n", (void *)f1);
        printf("g1: %p\n", (void *)g1);
        printf("h1: %p\n", (void *)h1);
        printf("i1: %p\n", (void *)i1);
        printf("i2: %p\n", (void *)i2);

        return 0;
    }

In this example, after filling the tcache with several freed chunks (7), the code frees chunk `h`, then chunk `i`, and then `h` again, causing a double free (also known as Fast Bin dup). This opens the possibility of receiving overlapping memory addresses when reallocating, meaning two or more pointers can point to the same memory location. Manipulating data through one pointer can then affect the other, creating a critical security risk and potential for exploitation.

Executing it, note how `i1` and `i2` got the same address:

    Initial allocations:
    a: 0xaaab0f0c22a0
    b: 0xaaab0f0c22c0
    c: 0xaaab0f0c22e0
    d: 0xaaab0f0c2300
    e: 0xaaab0f0c2320
    f: 0xaaab0f0c2340
    g: 0xaaab0f0c2360
    h: 0xaaab0f0c2380
    i: 0xaaab0f0c23a0
    After reallocations:
    a1: 0xaaab0f0c2360
    b1: 0xaaab0f0c2340
    c1: 0xaaab0f0c2320
    d1: 0xaaab0f0c2300
    e1: 0xaaab0f0c22e0
    f1: 0xaaab0f0c22c0
    g1: 0xaaab0f0c22a0
    h1: 0xaaab0f0c2380
    i1: 0xaaab0f0c23a0
    i2: 0xaaab0f0c23a0

## Examples

- Dragon Army. Hack The Box
  - We can only allocate Fast-Bin-sized chunks except for size `0x70`, which prevents the usual `__malloc_hook` overwrite.
  - Instead, we use PIE addresses that start with `0x56` as a target for Fast Bin dup (1/2 chance).
  - One place where PIE addresses are stored is in `main_arena`, which is inside Glibc and near `__malloc_hook`
  - We target a specific offset of `main_arena` to allocate a chunk there and continue allocating chunks until reaching `__malloc_hook` to get code execution.
- zero_to_hero. PicoCTF
  - Using Tcache bins and a null-byte overflow, we can achieve a double-free situation:
    - We allocate three chunks of size `0x110` (`A`, `B`, `C`)
    - We free `B`
    - We free `A` and allocate again to use the null-byte overflow
    - Now `B`'s size field is `0x100`, instead of `0x111`, so we can free it again
    - We have one Tcache-bin of size `0x110` and one of size `0x100` that point to the same address. So we have a double free.
  - We leverage the double free using Tcache poisoning

## References

- https://heap-exploitation.dhavalkapil.com/attacks/double_free

> [!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
> Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

> Support HackTricks
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.