Unlink Attack
Apoya a HackTricks
Revisa los planes de suscripción!
Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Información Básica
Cuando se descubrió este ataque, principalmente permitía un WWW (Write What Where), sin embargo, se agregaron algunas verificaciones haciendo que la nueva versión del ataque sea más interesante y más compleja y inútil.
Ejemplo de Código:
Código
```c #include #include #include #include
// Altered from https://github.com/DhavalKapil/heap-exploitation/tree/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/unlink_exploit.c to make it work
struct chunk_structure { size_t prev_size; size_t size; struct chunk_structure *fd; struct chunk_structure *bk; char buf[10]; // padding };
int main() { unsigned long long *chunk1, *chunk2; struct chunk_structure *fake_chunk, *chunk2_hdr; char data[20];
// First grab two chunks (non fast) chunk1 = malloc(0x8000); chunk2 = malloc(0x8000); printf("Stack pointer to chunk1: %p\n", &chunk1); printf("Chunk1: %p\n", chunk1); printf("Chunk2: %p\n", chunk2);
// Assuming attacker has control over chunk1's contents // Overflow the heap, override chunk2's header
// First forge a fake chunk starting at chunk1 // Need to setup fd and bk pointers to pass the unlink security check fake_chunk = (struct chunk_structure *)chunk1; fake_chunk->size = 0x8000; fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P
// Next modify the header of chunk2 to pass all security checks chunk2_hdr = (struct chunk_structure *)(chunk2 - 2); chunk2_hdr->prev_size = 0x8000; // chunk1's data region size chunk2_hdr->size &= ~1; // Unsetting prev_in_use bit
// Now, when chunk2 is freed, attacker's fake chunk is 'unlinked' // This results in chunk1 pointer pointing to chunk1 - 3 // i.e. chunk1[3] now contains chunk1 itself. // We then make chunk1 point to some victim's data free(chunk2); printf("Chunk1: %p\n", chunk1); printf("Chunk1[3]: %x\n", chunk1[3]);
chunk1[3] = (unsigned long long)data;
strcpy(data, "Victim's data");
// Overwrite victim's data using chunk1 chunk1[0] = 0x002164656b636168LL;
printf("%s\n", data);
return 0; }
</details>
* El ataque no funciona si se utilizan tcaches (después de la versión 2.26)
### Objetivo
Este ataque permite **cambiar un puntero a un chunk para que apunte a 3 direcciones antes de sí mismo**. Si esta nueva ubicación (alrededores de donde se encontraba el puntero) tiene información interesante, como otras asignaciones controlables / pila..., es posible leer/sobrescribirlas para causar un daño mayor.
* Si este puntero estaba ubicado en la pila, porque ahora apunta 3 direcciones antes de sí mismo y el usuario potencialmente puede leerlo y modificarlo, será posible filtrar información sensible de la pila o incluso modificar la dirección de retorno (quizás) sin tocar el canary.
* En ejemplos de CTF, este puntero está ubicado en un array de punteros a otras asignaciones, por lo tanto, al hacerlo apuntar 3 direcciones antes y poder leerlo y escribirlo, es posible hacer que los otros punteros apunten a otras direcciones.\
Como potencialmente el usuario también puede leer/escribir las otras asignaciones, puede filtrar información o sobrescribir nuevas direcciones en ubicaciones arbitrarias (como en la GOT).
### Requisitos
* Algún control en una memoria (por ejemplo, pila) para crear un par de chunks dando valores a algunos de los atributos.
* Fuga de pila para establecer los punteros del chunk falso.
### Ataque
* Hay un par de chunks (chunk1 y chunk2)
* El atacante controla el contenido de chunk1 y los encabezados de chunk2.
* En chunk1, el atacante crea la estructura de un chunk falso:
* Para evitar protecciones, se asegura de que el campo `size` sea correcto para evitar el error: `corrupted size vs. prev_size while consolidating`
* y los campos `fd` y `bk` del chunk falso apuntan a donde se almacena el puntero de chunk1 en la con desplazamientos de -3 y -2 respectivamente, por lo que `fake_chunk->fd->bk` y `fake_chunk->bk->fd` apuntan a la posición en la memoria (pila) donde se encuentra la dirección real de chunk1:
<figure><img src="../../.gitbook/assets/image (1245).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit">https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit</a></p></figcaption></figure>
* Los encabezados del chunk2 se modifican para indicar que el chunk anterior no se está utilizando y que el tamaño es el tamaño del chunk falso contenido.
* Cuando se libera el segundo chunk, entonces se desvincula este chunk falso:
* `fake_chunk->fd->bk` = `fake_chunk->bk`
* `fake_chunk->bk->fd` = `fake_chunk->fd`
* Anteriormente se hizo que `fake_chunk->fd->bk` y `fake_chunk->bk->fd` apunten al mismo lugar (la ubicación en la pila donde se almacenaba `chunk1`, por lo que era una lista enlazada válida). Como **ambos apuntan a la misma ubicación**, solo el último (`fake_chunk->bk->fd = fake_chunk->fd`) tendrá **efecto**.
* Esto **sobrescribirá el puntero a chunk1 en la pila a la dirección (o bytes) almacenados 3 direcciones antes en la pila**.
* Por lo tanto, si un atacante pudiera controlar nuevamente el contenido de chunk1, podrá **escribir dentro de la pila** pudiendo potencialmente sobrescribir la dirección de retorno saltando el canary y modificar los valores y puntos de las variables locales. Incluso modificando nuevamente la dirección de chunk1 almacenada en la pila a una ubicación diferente donde si el atacante pudiera controlar nuevamente el contenido de chunk1 podrá escribir en cualquier lugar.
* Tenga en cuenta que esto fue posible porque las **direcciones se almacenan en la pila**. El riesgo y la explotación pueden depender de **dónde se almacenan las direcciones del chunk falso**.
<figure><img src="../../.gitbook/assets/image (1246).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit">https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit</a></p></figcaption></figure>
## Referencias
* [https://heap-exploitation.dhavalkapil.com/attacks/unlink\_exploit](https://heap-exploitation.dhavalkapil.com/attacks/unlink\_exploit)
* Aunque sería extraño encontrar un ataque de unlink incluso en un CTF, aquí tienes algunos writeups donde se utilizó este ataque:
* Ejemplo de CTF: [https://guyinatuxedo.github.io/30-unlink/hitcon14\_stkof/index.html](https://guyinatuxedo.github.io/30-unlink/hitcon14\_stkof/index.html)
* En este ejemplo, en lugar de la pila hay un array de direcciones malloc'ed. El ataque de unlink se realiza para poder asignar un chunk aquí, por lo tanto, pudiendo controlar los punteros del array de direcciones malloc'ed. Luego, hay otra funcionalidad que permite modificar el contenido de los chunks en estas direcciones, lo que permite apuntar direcciones a la GOT, modificar direcciones de funciones para obtener filtraciones y RCE.
* Otro ejemplo de CTF: [https://guyinatuxedo.github.io/30-unlink/zctf16\_note2/index.html](https://guyinatuxedo.github.io/30-unlink/zctf16\_note2/index.html)
* Al igual que en el ejemplo anterior, hay un array de direcciones de asignaciones. Es posible realizar un ataque de unlink para hacer que la dirección de la primera asignación apunte a algunas posiciones antes de comenzar el array y luego sobrescribir esta asignación en la nueva posición. Por lo tanto, es posible sobrescribir punteros de otras asignaciones para apuntar a la GOT de atoi, imprimirla para obtener una filtración de libc y luego sobrescribir atoi GOT con la dirección a un one gadget.
* Ejemplo de CTF con funciones malloc y free personalizadas que abusan de una vulnerabilidad muy similar al ataque de unlink: [https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw17\_minesweeper/index.html](https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw17\_minesweeper/index.html)
* Hay un desbordamiento que permite controlar los punteros FD y BK de malloc personalizado que se liberará (personalizado). Además, el heap tiene el bit exec, por lo que es posible filtrar una dirección de heap y apuntar una función de la GOT a un chunk de heap con un shellcode para ejecutar.
<div data-gb-custom-block data-tag="hint" data-style='success'>
Aprende y practica Hacking en AWS:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Aprende y practica Hacking en GCP: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Apoya a HackTricks</summary>
* ¡Consulta los [**planes de suscripción**](https://github.com/sponsors/carlospolop)!
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Comparte trucos de hacking enviando PRs a los** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositorios de github.
</details>
</div>
Last updated