Heap Overflow

Apoya a HackTricks

Información Básica

Un desbordamiento de montón es como un desbordamiento de pila pero en el montón. Básicamente significa que se reservó un espacio en el montón para almacenar algunos datos y que los datos almacenados eran más grandes que el espacio reservado.

En los desbordamientos de pila sabemos que algunos registros como el puntero de instrucción o el marco de pila se restaurarán desde la pila y podría ser posible abusar de esto. En el caso de los desbordamientos de montón, no hay ninguna información sensible almacenada por defecto en el fragmento de montón que puede ser desbordado. Sin embargo, podría ser información sensible o punteros, por lo que la críticidad de esta vulnerabilidad depende de qué datos podrían ser sobrescritos y de cómo un atacante podría abusar de esto.

Para encontrar los desbordamientos de montón puedes usar los mismos patrones que en los desbordamientos de pila.

Desbordamientos de Pila vs Desbordamientos de Montón

En los desbordamientos de pila, la disposición y los datos que van a estar presentes en la pila en el momento en que se pueda activar la vulnerabilidad son bastante confiables. Esto se debe a que la pila es lineal, siempre aumentando en memoria colisionante, en lugares específicos de la ejecución del programa la memoria de la pila suele almacenar un tipo de datos similar y tiene una estructura específica con algunos punteros al final de la parte de la pila utilizada por cada función.

Sin embargo, en el caso de un desbordamiento de montón, la memoria utilizada no es lineal, sino que los fragmentos asignados suelen estar en posiciones separadas de la memoria (no uno al lado del otro) debido a contenedores y zonas que separan las asignaciones por tamaño y porque la memoria previamente liberada se utiliza antes de asignar nuevos fragmentos. Es complicado saber cuál es el objeto que va a colisionar con el vulnerable a un desbordamiento de montón. Por lo tanto, cuando se encuentra un desbordamiento de montón, es necesario encontrar una forma confiable de hacer que el objeto deseado esté a continuación en la memoria del que puede ser desbordado.

Una de las técnicas utilizadas para esto es el Aseo de Montón que se utiliza, por ejemplo, en este post. En el post se explica cómo en el núcleo de iOS, cuando una zona se queda sin memoria para almacenar fragmentos de memoria, la expande mediante una página de núcleo, y esta página se divide en fragmentos de los tamaños esperados que se utilizarían en orden (hasta la versión 9.2 de iOS, luego estos fragmentos se utilizan de manera aleatoria para dificultar la explotación de estos ataques).

Por lo tanto, en el post anterior donde ocurre un desbordamiento de montón, para forzar que el objeto desbordado colisione con un objeto víctima, se fuerzan varios kallocs mediante varios hilos para intentar asegurar que todos los fragmentos libres estén llenos y que se cree una nueva página.

Para forzar este llenado con objetos de un tamaño específico, la asignación fuera de línea asociada con un puerto mach de iOS es un candidato ideal. Al diseñar el tamaño del mensaje, es posible especificar exactamente el tamaño de la asignación de kalloc y cuando se destruye el puerto mach correspondiente, la asignación correspondiente se liberará inmediatamente de nuevo a kfree.

Luego, algunos de estos marcadores de posición pueden ser liberados. La lista de liberación de kalloc.4096 libera elementos en orden de último en entrar, primero en salir, lo que básicamente significa que si algunos marcadores de posición son liberados y el exploit intenta asignar varios objetos víctimas mientras intenta asignar el objeto vulnerable al desbordamiento, es probable que este objeto sea seguido por un objeto víctima.

Ejemplo libc

En esta página es posible encontrar una emulación básica de desbordamiento de montón que muestra cómo sobrescribir el bit previo en uso del siguiente fragmento y la posición del tamaño previo es posible consolidar un fragmento utilizado (haciéndolo creer que no está en uso) y luego asignarlo nuevamente pudiendo sobrescribir datos que se están utilizando en un puntero diferente también.

Otro ejemplo de protostar heap 0 muestra un ejemplo muy básico de un CTF donde un desbordamiento de montón puede ser abusado para llamar a la función ganadora y obtener la bandera.

En el ejemplo protostar heap 1 es posible ver cómo abusando de un desbordamiento de búfer es posible sobrescribir en un fragmento cercano una dirección donde se va a escribir datos arbitrarios del usuario.

Ejemplo ARM64

En la página https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/ puedes encontrar un ejemplo de desbordamiento de montón donde un comando que se va a ejecutar se almacena en el siguiente fragmento al fragmento desbordado. Por lo tanto, es posible modificar el comando ejecutado sobrescribiéndolo con un exploit sencillo como:

python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt

Otros ejemplos

  • Utilizamos una vulnerabilidad de Desbordamiento de Entero para obtener un Desbordamiento de Montón.

  • Corrompemos punteros a una función dentro de una struct del fragmento desbordado para establecer una función como system y lograr la ejecución de código.

Apoya a HackTricks

Last updated