hacktricks/binary-exploitation/libc-heap/unsorted-bin-attack.md

10 KiB

Atak na nieposortowany blok

{% hint style="success" %} Dowiedz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Dowiedz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)

Wesprzyj HackTricks
{% endhint %}

Podstawowe informacje

Aby uzyskać więcej informacji na temat tego, co oznacza nieposortowany blok, sprawdź tę stronę:

{% content-ref url="bins-and-memory-allocations.md" %} bins-and-memory-allocations.md {% endcontent-ref %}

Nieposortowane listy mogą zapisać adres w unsorted_chunks (av) w adresie bk fragmentu. Dlatego jeśli atakujący może zmodyfikować adres wskaźnika bk w fragmencie wewnątrz nieposortowanego bloku, może zapisać ten adres w dowolnym adresie, co może być pomocne do wycieku adresów Glibc lub obejścia niektórych zabezpieczeń.

W zasadzie ten atak pozwala ustawić dużą liczbę pod dowolnym adresem. Ta duża liczba to adres, który może być adresem sterty lub adresem Glibc. Typowym celem jest global_max_fast, aby umożliwić tworzenie szybkich bloków o większych rozmiarach (i przejście od ataku na nieposortowany blok do ataku na szybki blok).

{% hint style="success" %} Przyjrzenie się przykładowi podanemu w https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle i użycie 0x4000 i 0x5000 zamiast 0x400 i 0x500 jako rozmiarów fragmentów (aby uniknąć Tcache) pozwala zobaczyć, że obecnie błąd malloc(): unsorted double linked list corrupted jest wywoływany.

Dlatego ten atak na nieposortowany blok teraz (oprócz innych sprawdzeń) wymaga również naprawienia podwójnej listy połączonej, aby to ominąć victim->bk->fd == victim lub nie victim->fd == av (arena), co oznacza, że adres, gdzie chcemy zapisać, musi mieć adres fałszywego fragmentu w swojej pozycji fd i że fałszywy fragment fd wskazuje na arenę. {% endhint %}

{% hint style="danger" %} Zauważ, że ten atak psuje nieposortowany blok (a także mały i duży). Dlatego teraz możemy korzystać tylko z alokacji z szybkiego bloku (bardziej złożony program może wykonywać inne alokacje i się zawieszać), a aby to wywołać, musimy alokować ten sam rozmiar, w przeciwnym razie program się zawiesi.

Zauważ, że nadpisanie global_max_fast może pomóc w tym przypadku, zakładając, że szybki blok będzie w stanie obsłużyć wszystkie inne alokacje, dopóki exploit nie zostanie zakończony. {% endhint %}

Kod od guyinatuxedo dobrze to wyjaśnia, chociaż jeśli zmodyfikujesz alokacje pamięci, aby alokować pamięć wystarczająco dużą, aby nie trafić do Tcache, zobaczysz, że wcześniej wspomniany błąd uniemożliwia zastosowanie tej techniki: malloc(): unsorted double linked list corrupted

Atak na wyciek informacji z nieposortowanego bloku

To tak naprawdę bardzo podstawowe pojęcie. Fragmenty w nieposortowanym bloku będą miały wskaźniki. Pierwszy fragment w nieposortowanym bloku będzie faktycznie mieć linki fd i bk wskazujące na część głównej areny (Glibc).
Dlatego jeśli możesz umieścić fragment wewnątrz nieposortowanego bloku i odczytać go (użyj po zwolnieniu) lub ponownie go zaalokować bez nadpisywania co najmniej 1 z wskaźników, aby następnie go odczytać, możesz uzyskać wyciek informacji z Glibc.

Podobny atak użyty w tym opisie, polegał na wykorzystaniu struktury 4 fragmentów (A, B, C i D - D służył tylko do zapobiegania konsolidacji z górnym fragmentem), więc przepełnienie null bajtów w B zostało wykorzystane do spowodowania, że C wskazywało, że B jest nieużywane. Ponadto w B zmodyfikowano dane prev_size, więc rozmiar zamiast być rozmiarem B, był A+B.
Następnie C został zwolniony i zkonsolidowany z A+B (ale B nadal był używany). Zaalokowano nowy fragment o rozmiarze A, a następnie wyciekły adresy Glibc, które zostały zapisane w B, skąd zostały wycieknięte.

Odwołania i inne przykłady

  • https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap
  • Celem jest nadpisanie zmiennej globalnej wartością większą niż 4869, aby można było uzyskać flagę, a PIE nie jest włączone.
  • Możliwe jest generowanie fragmentów o dowolnych rozmiarach i występuje przepełnienie sterty o pożądanym rozmiarze.
  • Atak rozpoczyna się od utworzenia 3 fragmentów: fragmentu0 do wykorzystania przepełnienia, fragmentu1 do przepełnienia i fragmentu2, aby górny fragment nie konsolidował poprzednich.
  • Następnie fragment1 jest zwalniany, a fragment0 jest przepełniany, aby wskaźnik bk fragmentu1 wskazywał na: bk = magic - 0x10
  • Następnie alokowany jest fragment3 o tym samym rozmiarze co fragment1, co spowoduje atak na nieposortowany blok i zmodyfikuje wartość zmiennej globalnej, umożliwiając uzyskanie flagi.
  • https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html
  • Funkcja łączenia jest podatna, ponieważ jeśli oba przekazane indeksy są takie same, to zrealokuje na nim i zwolni go, ale zwróci wskaźnik do tego zwolnionego obszaru, który można wykorzystać.
  • Dlatego tworzone są 2 fragmenty: fragment0, który zostanie połączony ze sobą i fragment1, aby zapobiec konsolidacji z górnym fragmentem. Następnie funkcja merge jest wywoływana z fragmentem0 dwukrotnie, co spowoduje użycie po zwolnieniu.
  • Następnie wywoływana jest funkcja view z indeksem 2 (który jest indeksem używanego po zwolnieniu fragmentu), co spowoduje wyciek adresu libc.
  • Ponieważ binarny ma zabezpieczenia, aby alokować tylko rozmiary większe niż global_max_fast, więc nie używany jest szybki blok, atak na nieposortowany blok zostanie wykorzystany do nadpisania zmiennej globalnej global_max_fast.
  • Następnie możliwe jest wywołanie funkcji edycji z indeksem 2 (wskaźnik używany po zwolnieniu) i nadpisanie wskaźnika bk, aby wskazywał na p64(global_max_fast-0x10). Następnie tworzenie nowego fragmentu użyje wcześniej skompromitowanego adresu zwolnienia (0x20) i wywoła atak na nieposortowany blok, nadpisując global_max_fast dużą wartością, co teraz pozwala na tworzenie fragmentów w szybkich blokach.
  • Teraz wykonywany jest atak na szybki blok:
  • Po pierwsze odkryto, że możliwe jest pracowanie z szybkimi fragmentami o rozmiarze 200 w lokalizacji __free_hook:
  • gef➤  p &__free_hook
    

$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook> gef➤ x/60gx 0x7ff1e9e607a8 - 0x59 0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200 0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000

  • Jeśli uda nam się uzyskać szybki kawałek o rozmiarze 0x200 w tym miejscu, będzie możliwe nadpisanie wskaźnika funkcji, który zostanie wykonany
  • W tym celu tworzony jest nowy kawałek o rozmiarze 0xfc i funkcja scalająca jest wywoływana z tym wskaźnikiem dwukrotnie, w ten sposób uzyskujemy wskaźnik do zwolnionego kawałka o rozmiarze 0xfc*2 = 0x1f8 w szybkim pojemniku.
  • Następnie funkcja edycji jest wywoływana w tym kawałku, aby zmodyfikować adres fd tego szybkiego pojemnika wskazujący na poprzednią funkcję __free_hook.
  • Następnie tworzony jest kawałek o rozmiarze 0x1f8 w celu pobrania z szybkiego pojemnika poprzedniego nieużytecznego kawałka, więc tworzony jest kolejny kawałek o rozmiarze 0x1f8, aby uzyskać kawałek z szybkiego pojemnika w __free_hook, który jest nadpisany adresem funkcji system.
  • I wreszcie zwalniany jest kawałek zawierający ciąg znaków /bin/sh\x00, wywołując funkcję usuwania, co powoduje wywołanie funkcji __free_hook, która wskazuje na system z parametrem /bin/sh\x00.
  • CTF https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html
  • Kolejny przykład nadużycia przepełnienia o 1B w celu skonsolidowania kawałków w nieuporządkowanym pojemniku i uzyskania wycieku informacji o libc, a następnie przeprowadzenia ataku na szybki pojemnik w celu nadpisania haka malloc adresem jednego gadżetu
  • Robot Factory. BlackHat MEA CTF 2022
  • Możemy przydzielać tylko kawałki o rozmiarze większym niż 0x100.
  • Nadpisanie global_max_fast za pomocą ataku na nieuporządkowany pojemnik (działa 1/16 razy ze względu na ASLR, ponieważ musimy zmodyfikować 12 bitów, ale musimy zmodyfikować 16 bitów).
  • Atak na szybki pojemnik w celu zmodyfikowania globalnej tablicy kawałków. Zapewnia to arbitralne odczyt/zapis, co pozwala na modyfikację GOT i ustawienie pewnej funkcji na wskazanie system.