Unsorted Bin Attack
Last updated
Last updated
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aby uzyskać więcej informacji na temat tego, czym jest niesortowany koszyk, sprawdź tę stronę:
Niesortowane listy mogą zapisać adres do unsorted_chunks (av)
w adresie bk
kawałka. Dlatego, jeśli atakujący może zmodyfikować adres wskaźnika bk
w kawałku wewnątrz niesortowanego koszyka, mógłby być w stanie zapisać ten adres w dowolnym adresie, co mogłoby być pomocne do wycieku adresów Glibc lub obejścia niektórych zabezpieczeń.
Tak więc, zasadniczo, ten atak pozwala na ustawienie dużej liczby w dowolnym adresie. 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 koszyków o większych rozmiarach (i przejście z ataku na niesortowany koszyk do ataku na szybki koszyk).
Patrząc na przykład podany w https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle i używając 0x4000 i 0x5000 zamiast 0x400 i 0x500 jako rozmiarów kawałków (aby uniknąć Tcache), można zobaczyć, że obecnie błąd malloc(): niesortowana podwójnie powiązana lista uszkodzona
jest wyzwalany.
Dlatego ten atak na niesortowany koszyk teraz (wśród innych kontroli) również wymaga możliwości naprawienia podwójnie powiązanej listy, aby to obejść victim->bk->fd == victim
lub nie victim->fd == av (arena)
, co oznacza, że adres, w którym chcemy zapisać, musi mieć adres fałszywego kawałka w swojej pozycji fd
, a fałszywy kawałek fd
wskazuje na arenę.
Zauważ, że ten atak psuje niesortowany koszyk (stąd mały i duży również). Dlatego możemy teraz używać tylko alokacji z szybkiego koszyka (bardziej złożony program może wykonać inne alokacje i się zawiesić), a aby to wyzwolić, musimy alokować ten sam rozmiar, w przeciwnym razie program się zawiesi.
Zauważ, że nadpisanie global_max_fast
może pomóc w tym przypadku, ufając, że szybki koszyk będzie w stanie zająć się wszystkimi innymi alokacjami, aż do zakończenia eksploatu.
Kod z guyinatuxedo wyjaśnia to bardzo dobrze, chociaż jeśli zmodyfikujesz mallocy, aby alokować pamięć wystarczająco dużą, aby nie skończyć w Tcache, możesz zobaczyć, że wcześniej wspomniany błąd pojawia się, uniemożliwiając tę technikę: malloc(): niesortowana podwójnie powiązana lista uszkodzona
To w rzeczywistości bardzo podstawowa koncepcja. Kawałki w niesortowanym koszyku będą miały wskaźniki. Pierwszy kawałek w niesortowanym koszyku będzie miał fd
i bk
linki wskazujące na część głównej areny (Glibc).
Dlatego, jeśli możesz włożyć kawałek do niesortowanego koszyka i go odczytać (użycie po zwolnieniu) lub ponownie go alokować bez nadpisywania przynajmniej 1 z wskaźników, aby następnie go odczytać, możesz uzyskać wyciek informacji Glibc.
Podobny atak użyty w tym opisie polegał na nadużywaniu struktury 4 kawałków (A, B, C i D - D jest tylko po to, aby zapobiec konsolidacji z górnym kawałkiem), więc użyto przepełnienia bajtu null w B, aby sprawić, że C wskazywało, że B był nieużywany. Ponadto w B zmodyfikowano dane prev_size
, aby rozmiar zamiast rozmiaru B wynosił A+B.
Następnie C został zwolniony i skonsolidowany z A+B (ale B wciąż był używany). Nowy kawałek o rozmiarze A został alokowany, a następnie adresy wycieków libc zostały zapisane w B, skąd zostały wycieknięte.
Celem jest nadpisanie zmiennej globalnej wartością większą niż 4869, aby możliwe było uzyskanie flagi, a PIE nie jest włączone.
Możliwe jest generowanie kawałków o dowolnych rozmiarach, a także występuje przepełnienie sterty o pożądanym rozmiarze.
Atak zaczyna się od stworzenia 3 kawałków: chunk0 do nadużywania przepełnienia, chunk1 do przepełnienia i chunk2, aby górny kawałek nie konsolidował poprzednich.
Następnie chunk1 jest zwalniany, a chunk0 jest przepełniany, aby wskaźnik bk
chunk1 wskazywał na: bk = magic - 0x10
Następnie chunk3 jest alokowany o tym samym rozmiarze co chunk1, co wyzwoli atak na niesortowany koszyk i zmodyfikuje wartość zmiennej globalnej, co umożliwi uzyskanie flagi.
Funkcja merge jest podatna, ponieważ jeśli oba przekazane indeksy są takie same, to zrealokuje ją i następnie zwolni, ale zwróci wskaźnik do tego zwolnionego obszaru, który można wykorzystać.
Dlatego tworzone są 2 kawałki: chunk0, który zostanie scalony z samym sobą, oraz chunk1, aby zapobiec konsolidacji z górnym kawałkiem. Następnie funkcja merge jest wywoływana z chunk0 dwukrotnie, co spowoduje użycie po zwolnieniu.
Następnie funkcja view
jest wywoływana z indeksem 2 (który jest indeksem kawałka używanego po zwolnieniu), co wycieka adres libc.
Ponieważ binarka ma zabezpieczenia, aby tylko mallocować rozmiary większe niż global_max_fast
, więc żaden szybki koszyk nie jest używany, zostanie użyty atak na niesortowany koszyk, aby nadpisać zmienną globalną global_max_fast
.
Następnie możliwe jest wywołanie funkcji edytora z indeksem 2 (wskaźnik używany po zwolnieniu) i nadpisanie wskaźnika bk
, aby wskazywał na p64(global_max_fast-0x10)
. Następnie, tworząc nowy kawałek, użyje wcześniej skompromitowanego adresu zwolnionego (0x20), co wyzwoli atak na niesortowany koszyk, nadpisując global_max_fast
, co jest bardzo dużą wartością, co teraz pozwala na tworzenie kawałków w szybkich koszykach.
Teraz przeprowadzany jest atak na szybki koszyk:
Przede wszystkim odkryto, że możliwe jest pracowanie z szybkimi kawałkami o rozmiarze 200 w lokalizacji __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 tej lokalizacji, będzie możliwe nadpisanie wskaźnika funkcji, który zostanie wykonany.
W tym celu tworzony jest nowy kawałek o rozmiarze 0xfc
, a funkcja merge 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 koszyku.
Następnie funkcja edytora jest wywoływana w tym kawałku, aby zmodyfikować adres fd
tego szybkiego koszyka, aby wskazywał na poprzednią funkcję __free_hook
.
Następnie tworzony jest kawałek o rozmiarze 0x1f8
, aby odzyskać z szybkiego koszyka poprzedni bezużyteczny kawałek, więc tworzony jest kolejny kawałek o rozmiarze 0x1f8
, aby uzyskać kawałek szybkiego koszyka w __free_hook
, który jest nadpisywany adresem funkcji system
.
A na koniec kawałek zawierający ciąg /bin/sh\x00
jest zwalniany, wywołując funkcję usuwania, co wyzwala funkcję __free_hook
, która wskazuje na system z /bin/sh\x00
jako parametrem.
Inny przykład nadużywania przepełnienia 1B do konsolidacji kawałków w niesortowanym koszyku i uzyskania wycieku informacji libc, a następnie przeprowadzenia ataku na szybki koszyk w celu nadpisania haka malloc z adresem jednego gadżetu.
Możemy alokować tylko kawałki o rozmiarze większym niż 0x100
.
Nadpisz global_max_fast
używając ataku na niesortowany koszyk (działa 1/16 razy z powodu ASLR, ponieważ musimy zmodyfikować 12 bitów, ale musimy zmodyfikować 16 bitów).
Atak na szybki koszyk w celu modyfikacji globalnej tablicy kawałków. To daje dowolną prymitywę odczytu/zapisu, co pozwala na modyfikację GOT i ustawienie niektórej funkcji, aby wskazywała na system
.
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)