Double Free

Support HackTricks

Basic Information

Якщо ви звільняєте блок пам'яті більше ніж один раз, це може порушити дані аллокатора і відкрити двері для атак. Ось як це відбувається: коли ви звільняєте блок пам'яті, він повертається до списку вільних частин (наприклад, "швидкий бін"). Якщо ви звільняєте той самий блок двічі підряд, аллокатор виявляє це і видає помилку. Але якщо ви звільняєте іншу частину між цим, перевірка на подвійне звільнення обходиться, що призводить до пошкодження.

Тепер, коли ви запитуєте нову пам'ять (використовуючи malloc), аллокатор може надати вам блок, який був звільнений двічі. Це може призвести до того, що два різні вказівники вказують на одне й те саме місце в пам'яті. Якщо зловмисник контролює один з цих вказівників, він може змінити вміст цієї пам'яті, що може викликати проблеми з безпекою або навіть дозволити йому виконати код.

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;
}

У цьому прикладі, після заповнення tcache кількома звільненими частинами (7), код звільняє частину h, потім частину i, а потім знову h, що викликає подвійне звільнення (також відоме як Fast Bin dup). Це відкриває можливість отримання перекриваючих адрес пам'яті під час повторного виділення, що означає, що два або більше вказівників можуть вказувати на одне й те саме місце в пам'яті. Маніпулювання даними через один вказівник може вплинути на інший, створюючи критичний ризик безпеки та потенціал для експлуатації.

Виконуючи це, зверніть увагу, як i1 і i2 отримали одну й ту ж адресу:

Початкові виділення:
a: 0xaaab0f0c22a0
b: 0xaaab0f0c22c0
c: 0xaaab0f0c22e0
d: 0xaaab0f0c2300
e: 0xaaab0f0c2320
f: 0xaaab0f0c2340
g: 0xaaab0f0c2360
h: 0xaaab0f0c2380
i: 0xaaab0f0c23a0
Після повторних виділень:
a1: 0xaaab0f0c2360
b1: 0xaaab0f0c2340
c1: 0xaaab0f0c2320
d1: 0xaaab0f0c2300
e1: 0xaaab0f0c22e0
f1: 0xaaab0f0c22c0
g1: 0xaaab0f0c22a0
h1: 0xaaab0f0c2380
i1: 0xaaab0f0c23a0
i2: 0xaaab0f0c23a0

Приклади

  • Ми можемо виділяти лише частини розміру Fast-Bin, за винятком розміру 0x70, що запобігає звичайному переписуванню __malloc_hook.

  • Натомість ми використовуємо адреси PIE, які починаються з 0x56, як ціль для Fast Bin dup (1/2 шанс).

  • Одне місце, де зберігаються адреси PIE, - це main_arena, який знаходиться всередині Glibc і поруч з __malloc_hook.

  • Ми націлюємося на конкретний зсув main_arena, щоб виділити частину там і продовжувати виділяти частини, поки не досягнемо __malloc_hook, щоб отримати виконання коду.

  • Використовуючи Tcache bins і переповнення нульовим байтом, ми можемо досягти ситуації з подвійним звільненням:

  • Ми виділяємо три частини розміру 0x110 (A, B, C)

  • Ми звільняємо B

  • Ми звільняємо A і знову виділяємо, щоб використати переповнення нульовим байтом

  • Тепер поле розміру B становить 0x100, замість 0x111, тому ми можемо звільнити його знову

  • У нас є один Tcache-bin розміру 0x110 і один розміру 0x100, які вказують на одну й ту ж адресу. Отже, у нас є подвійне звільнення.

  • Ми використовуємо подвійне звільнення за допомогою Tcache poisoning

Посилання

Підтримати HackTricks

Last updated