Desbordamiento por uno

Reading time: 6 minutes

tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Apoya a HackTricks

Información Básica

Tener acceso a un desbordamiento de 1B permite a un atacante modificar el campo size del siguiente chunk. Esto permite manipular qué chunks están realmente liberados, generando potencialmente un chunk que contiene otro chunk legítimo. La explotación es similar a double free o chunks superpuestos.

Hay 2 tipos de vulnerabilidades de desbordamiento por uno:

  • Byte arbitrario: Este tipo permite sobrescribir ese byte con cualquier valor.
  • Byte nulo (off-by-null): Este tipo permite sobrescribir ese byte solo con 0x00.
  • Un ejemplo común de esta vulnerabilidad se puede ver en el siguiente código donde el comportamiento de strlen y strcpy es inconsistente, lo que permite establecer un byte 0x00 al principio del siguiente chunk.
  • Esto puede ser explotado con House of Einherjar.
  • Si se utiliza Tcache, esto puede aprovecharse para una situación de double free.
Off-by-null
c
// From https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/
int main(void)
{
char buffer[40]="";
void *chunk1;
chunk1 = malloc(24);
puts("Get Input");
gets(buffer);
if(strlen(buffer)==24)
{
strcpy(chunk1,buffer);
}
return 0;
}

Entre otras verificaciones, ahora cada vez que un bloque está libre, el tamaño anterior se compara con el tamaño configurado en el bloque de metadatos, lo que hace que este ataque sea bastante complejo a partir de la versión 2.28.

Ejemplo de código:

Objetivo

  • Hacer que un bloque esté contenido dentro de otro bloque, de modo que el acceso de escritura sobre ese segundo bloque permita sobrescribir el contenido del primero.

Requisitos

  • Desbordamiento off by one para modificar la información de metadatos del tamaño.

Ataque general off-by-one

  • Asignar tres bloques A, B y C (digamos tamaños 0x20), y otro para evitar la consolidación con el bloque superior.
  • Liberar C (insertado en la lista libre Tcache de 0x20).
  • Usar el bloque A para desbordar sobre B. Abusar del off-by-one para modificar el campo size de B de 0x21 a 0x41.
  • Ahora tenemos B conteniendo el bloque libre C.
  • Liberar B y asignar un bloque de 0x40 (se colocará aquí nuevamente).
  • Podemos modificar el puntero fd de C, que sigue estando libre (envenenamiento de Tcache).

Ataque off-by-null

  • Se reservan 3 bloques de memoria (a, b, c) uno tras otro. Luego, se libera el del medio. El primero contiene una vulnerabilidad de desbordamiento off by one y el atacante abusa de ella con un 0x00 (si el byte anterior era 0x10, haría que el bloque del medio indicara que es 0x10 más pequeño de lo que realmente es).
  • Luego, se asignan 2 bloques más pequeños en el bloque liberado del medio (b), sin embargo, como b + b->size nunca actualiza el bloque c porque la dirección apuntada es más pequeña de lo que debería.
  • Luego, b1 y c se liberan. Como c - c->prev_size aún apunta a b (ahora b1), ambos se consolidan en un solo bloque. Sin embargo, b2 sigue estando entre b1 y c.
  • Finalmente, se realiza un nuevo malloc reclamando esta área de memoria que en realidad contendrá b2, permitiendo al propietario del nuevo malloc controlar el contenido de b2.

Esta imagen explica perfectamente el ataque:

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

Otros Ejemplos y Referencias

  • https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks
  • Bon-nie-appetit. HTB Cyber Apocalypse CTF 2022
  • Off-by-one debido a que strlen considera el campo size del siguiente bloque.
  • Se está utilizando Tcache, por lo que un ataque general off-by-one funciona para obtener una primitiva de escritura arbitraria con envenenamiento de Tcache.
  • Asis CTF 2016 b00ks
  • Es posible abusar de un off by one para filtrar una dirección del heap porque el byte 0x00 al final de una cadena está siendo sobrescrito por el siguiente campo.
  • La escritura arbitraria se obtiene abusando del off by one para hacer que el puntero apunte a otro lugar donde se construirá una estructura falsa con punteros falsos. Luego, es posible seguir el puntero de esta estructura para obtener escritura arbitraria.
  • La dirección de libc se filtra porque si el heap se extiende usando mmap, la memoria asignada por mmap tiene un desplazamiento fijo desde libc.
  • Finalmente, se abusa de la escritura arbitraria para escribir en la dirección de __free_hook con un one gadget.
  • plaidctf 2015 plaiddb
  • Hay una vulnerabilidad de NULL off by one en la función getline que lee líneas de entrada del usuario. Esta función se utiliza para leer la "clave" del contenido y no el contenido.
  • En el informe se crean 5 bloques iniciales:
  • chunk1 (0x200)
  • chunk2 (0x50)
  • chunk5 (0x68)
  • chunk3 (0x1f8)
  • chunk4 (0xf0)
  • chunk defensa (0x400) para evitar la consolidación con el bloque superior.
  • Luego, se liberan los bloques 1, 5 y 3, así que:

[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defensa ]

- Luego, abusando de chunk3 (0x1f8), se abusa del off-by-one nulo escribiendo el prev_size como `0x4e0`.
- Nota cómo los tamaños de los bloques inicialmente asignados 1, 2, 5 y 3 más los encabezados de 4 de esos bloques suman `0x4e0`: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- Luego, se libera el bloque 4, generando un bloque que consume todos los bloques hasta el principio:
- ```python
[ 0x4e0 Chunk 1-2-5-3 (free) ] [ 0xf0 Chunk 4 (corrupted) ] [ 0x400 Chunk defensa ]

[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defensa ]