Unsorted Bin Attack
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)
Podstawowe informacje
Aby uzyskać więcej informacji na temat tego, co oznacza nieposortowany blok, sprawdź tę stronę:
Bins & Memory AllocationsNieposortowane 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).
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ę.
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.
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
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.
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 globalnejglobal_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ł nap64(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ącglobal_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
:
$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 rozmiarze0xfc*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 rozmiarze0x1f8
, aby uzyskać kawałek z szybkiego pojemnika w__free_hook
, który jest nadpisany adresem funkcjisystem
.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
.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
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
.
Last updated