hacktricks/binary-exploitation/heap/double-free.md

5.9 KiB

Doble Liberación

Aprende hacking en AWS de cero a héroe con htARTE (Experto en Equipo Rojo de AWS de HackTricks)!

Otras formas de apoyar a HackTricks:

Información Básica

Si liberas un bloque de memoria más de una vez, puede alterar los datos del asignador y abrir la puerta a ataques. Así es como sucede: cuando liberas un bloque de memoria, vuelve a una lista de fragmentos libres (por ejemplo, el "fastbin"). Si liberas el mismo bloque dos veces seguidas, el asignador detecta esto y arroja un error. Pero si liberas otro fragmento en medio, se omite la verificación de doble liberación, causando corrupción.

Ahora, cuando solicitas nueva memoria (usando malloc), el asignador podría darte un bloque que ha sido liberado dos veces. Esto puede llevar a que dos punteros diferentes apunten a la misma ubicación de memoria. Si un atacante controla uno de esos punteros, puede cambiar el contenido de esa memoria, lo que puede causar problemas de seguridad o incluso permitirles ejecutar código.

Ejemplo:

#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 *)i1);

return 0;
}

En este ejemplo, después de llenar la tcache con varios bloques liberados, el código libera el bloque h, luego el bloque i, y luego nuevamente h, causando un error de doble liberación. Esto abre la posibilidad de recibir direcciones de memoria superpuestas al realojar, lo que significa que dos o más punteros pueden apuntar a la misma ubicación de memoria. Manipular datos a través de un puntero puede afectar al otro, creando un riesgo de seguridad crítico y potencial para la explotación.

Al ejecutarlo, observe cómo i1 e i2 obtienen la misma dirección:

Asignaciones iniciales:
a: 0xaaab0f0c22a0
b: 0xaaab0f0c22c0
c: 0xaaab0f0c22e0
d: 0xaaab0f0c2300
e: 0xaaab0f0c2320
f: 0xaaab0f0c2340
g: 0xaaab0f0c2360
h: 0xaaab0f0c2380
i: 0xaaab0f0c23a0
Después de los realojamientos:
a1: 0xaaab0f0c2360
b1: 0xaaab0f0c2340
c1: 0xaaab0f0c2320
d1: 0xaaab0f0c2300
e1: 0xaaab0f0c22e0
f1: 0xaaab0f0c22c0
g1: 0xaaab0f0c22a0
h1: 0xaaab0f0c2380
i1: 0xaaab0f0c23a0
i2: 0xaaab0f0c23a0

Referencias

Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks: