diff --git a/src/binary-exploitation/libc-heap/unsorted-bin-attack.md b/src/binary-exploitation/libc-heap/unsorted-bin-attack.md index 5709c2636..2748f7a92 100644 --- a/src/binary-exploitation/libc-heap/unsorted-bin-attack.md +++ b/src/binary-exploitation/libc-heap/unsorted-bin-attack.md @@ -1,55 +1,113 @@ -# Atak na Niezorganizowany Koszyk +# Unsorted Bin Attack {{#include ../../banners/hacktricks-training.md}} -## Podstawowe Informacje +## Podstawowe informacje + +Aby uzyskać więcej informacji o tym, czym jest unsorted bin sprawdź tę stronę: -Aby uzyskać więcej informacji na temat tego, czym jest niezorganizowany koszyk, sprawdź tę stronę: {{#ref}} bins-and-memory-allocations.md {{#endref}} -Niezorganizowane 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 niezorganizowanego koszyka, może być w stanie **zapisać ten adres w dowolnym adresie**, co może być pomocne do wycieku adresów Glibc lub obejścia niektórych zabezpieczeń. +Unsorted lists mogą zapisać adres `unsorted_chunks (av)` w polu `bk` chunku. Dlatego, jeśli atakujący potrafi **zmodyfikować adres wskaźnika `bk`** w chunku znajdującym się w unsorted bin, może być w stanie **zapisać ten adres pod dowolnym adresem**, co może pomóc w leakowaniu adresów Glibc lub obejściu pewnych zabezpieczeń. -Tak więc, w zasadzie, 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 koszyków szybkich o większych rozmiarach (i przejście z ataku na niezorganizowany koszyk do ataku na koszyk szybki). +Tak więc w praktyce ten atak pozwala **ustawić dużą wartość pod dowolnym adresem**. Ta duża wartość to adres, który może być adresem heap lub Glibc. Tradycyjnym celem było **`global_max_fast`**, aby umożliwić tworzenie fast binów o większych rozmiarach (i przejście z unsorted bin attack do fast bin attack). + +- Uwaga (glibc ≥ 2.39): `global_max_fast` stał się globalem 8‑bitowym. Bezmyślne zapisanie tam wskaźnika przez unsorted‑bin write nadpisze sąsiednie dane libc i nie podniesie niezawodnie limitu fastbin. Lepiej wybierać inne cele lub inne prymitywy przy atakowaniu glibc 2.39+. Zobacz "Modern constraints" poniżej i rozważ łączenie z innymi technikami, jak [large bin attack](large-bin-attack.md) lub [fast bin attack](fast-bin-attack.md), gdy masz stabilny prymityw. > [!TIP] -> Zobaczenie przykładu podanego w [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle](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 kawałków (aby uniknąć Tcache) pozwala zobaczyć, że **obecnie** błąd **`malloc(): unsorted double linked list corrupted`** jest wyzwalany. +> T> Przejrzenie przykładu podanego w [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle) i użycie 0x4000 oraz 0x5000 zamiast 0x400 i 0x500 jako rozmiarów chunków (aby uniknąć Tcache) pokazuje, że **dziś** wywoływany jest błąd **`malloc(): unsorted double linked list corrupted`**. > -> Dlatego ten atak na niezorganizowany koszyk teraz (wśród innych kontroli) również wymaga możliwości naprawienia podwójnie powiązanej listy, aby to było obejście `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ę. +> W związku z tym ten unsorted bin attack obecnie (oprócz innych sprawdzeń) wymaga także naprawienia listy dwukierunkowej, żeby obejść `victim->bk->fd == victim` lub `victim->fd == av (arena)`, co oznacza, że adres, pod który chcemy zapisać, musi mieć adres fałszywego chunku w swoim polu `fd`, oraz że `fd` fałszywego chunku wskazuje na arena. > [!CAUTION] -> Zauważ, że ten atak psuje niezorganizowany 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, inaczej program się zawiesi.** +> Uwaga, ten atak korumpuje unsorted bin (a więc także small i large). Możemy więc teraz tylko **używać alokacji z fast bin** (bardziej złożony program może wykonywać inne alokacje i się zawiesić), i aby wywołać to musimy **alokować tę samą wielkość, w przeciwnym razie program się rozbije.** > -> 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. +> Nadpisanie **`global_max_fast`** może w tym przypadku pomóc, zakładając, że fast bin poradzi sobie ze wszystkimi innymi alokacjami do czasu zakończenia exploitu. -Kod z [**guyinatuxedo**](https://guyinatuxedo.github.io/31-unsortedbin_attack/unsorted_explanation/index.html) 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(): unsorted double linked list corrupted`** +Kod od [**guyinatuxedo**](https://guyinatuxedo.github.io/31-unsortedbin_attack/unsorted_explanation/index.html) wyjaśnia to bardzo dobrze, chociaż jeśli zmodyfikujesz mallocy tak, by alokowały pamięć na tyle dużą, żeby nie kończyć w Tcache, można zobaczyć wspomniany wcześniej błąd zapobiegający tej technice: **`malloc(): unsorted double linked list corrupted`** -## Atak na Wycieki Informacji z Niezorganizowanego Koszyka +### Jak zapis faktycznie zachodzi -To w rzeczywistości bardzo podstawowa koncepcja. Kawałki w niezorganizowanym koszyku będą miały wskaźniki. Pierwszy kawałek w niezorganizowanym koszyku będzie miał **`fd`** i **`bk`** linki **wskazujące na część głównej areny (Glibc)**.\ -Dlatego, jeśli możesz **umieścić kawałek wewnątrz niezorganizowanego koszyka i go odczytać** (użycie po zwolnieniu) lub **ponownie go alokować bez nadpisywania przynajmniej 1 z wskaźników**, aby następnie **odczytać** go, możesz uzyskać **wyciek informacji Glibc**. +- Unsorted‑bin write jest wyzwalany przy `free`, gdy zwolniony chunk jest wstawiany na początek unsorted listy. +- Podczas wstawiania alokator wykonuje: `bck = unsorted_chunks(av); fwd = bck->fd; victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim;` +- Jeśli możesz ustawić `victim->bk` na `(mchunkptr)(TARGET - 0x10)` przed wywołaniem `free(victim)`, to ostatnie przypisanie wykona zapis: `*(TARGET) = victim`. +- Później, kiedy alokator przetwarza unsorted bin, sprawdzenia integralności potwierdzą (m.in.), że `bck->fd == victim` oraz `victim->fd == unsorted_chunks(av)` zanim wykona unlink. Ponieważ podczas wstawiania już zapisano `victim` w `bck->fd` (naszym `TARGET`), te sprawdzenia mogą zostać spełnione jeśli zapis się powiódł. -Podobny [**atak użyty w tym opisie**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html) 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 zerowego w B, aby sprawić, że C wskazywał, że B był nieużywany. Ponadto w B zmodyfikowano dane `prev_size`, aby rozmiar zamiast być rozmiarem B był 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. +## Ograniczenia w nowych wersjach (glibc ≥ 2.33) -## Odniesienia i Inne Przykłady +Aby używać unsorted‑bin writes niezawodnie na aktualnym glibc: + +- Tcache interference: dla rozmiarów mieszczących się w tcache, free są przekierowywane tam i nie trafiają do unsorted bin. Można: + - robić żądania o rozmiarach > MAX_TCACHE_SIZE (≥ 0x410 na 64‑bit domyślnie), lub + - zapełnić odpowiadający bin tcache (7 wpisów), tak aby kolejne free trafiły do global bins, lub + - jeśli środowisko jest kontrolowane, wyłączyć tcache (np. GLIBC_TUNABLES glibc.malloc.tcache_count=0). +- Sprawdzenia integralności na unsorted list: na ścieżce alokacji, która bada unsorted bin, glibc sprawdza (uproszczone): + - `bck->fd == victim` oraz `victim->fd == unsorted_chunks(av)`; w przeciwnym razie przerywa działanie z `malloc(): unsorted double linked list corrupted`. +- To oznacza, że adres, który atakujesz, musi tolerować dwa zapisy: najpierw `*(TARGET) = victim` w czasie free; później, gdy chunk jest usuwany, `*(TARGET) = unsorted_chunks(av)` (alokator nadpisuje `bck->fd` z powrotem adresem głowy binu). Wybierz cele, gdzie wymuszenie dużej, niezerowej wartości jest użyteczne. +- Typowe stabilne cele we współczesnych exploitach: + - stan aplikacji lub globalny stan traktujący "duże" wartości jako flagi/limity, + - pośrednie prymitywy (np. przygotowanie do późniejszego [fast bin attack]({{#ref}}fast-bin-attack.md{{#endref}}) lub pivot dla kolejnego write‑what‑where). +- Unikaj `__malloc_hook`/`__free_hook` w nowych glibc: zostały usunięte w 2.34. Unikaj `global_max_fast` w wersjach ≥ 2.39 (zob. powyżej). + +- O `global_max_fast` w nowszym glibc + - W glibc 2.39+ `global_max_fast` jest globalem 8‑bitowym. Klasyczny trik zapisania wskaźnika heap tam (by powiększyć fastbins) już nie działa czysto i prawdopodobnie skazi sąsiedni stan alokatora. Lepiej stosować inne strategie. + +## Minimalny przepis na eksploatację (nowoczesny glibc) + +Cel: uzyskać pojedynczy arbitralny zapis wskaźnika heap na dowolny adres przy użyciu prymitywu wstawiania unsorted‑bin, bez wywoływania crasha. + +- Layout/grooming + - Alokuj A, B, C o rozmiarach wystarczająco dużych, by ominąć tcache (np. 0x5000). C zapobiega konsolidacji z top chunk. +- Corruption + - Overflow z A do nagłówka chunku B, aby ustawić `B->bk = (mchunkptr)(TARGET - 0x10)`. +- Trigger + - `free(B)`. W czasie wstawiania alokator wykona `bck->fd = B`, więc `*(TARGET) = B`. +- Kontynuacja + - Jeśli planujesz kontynuować alokacje i program używa unsorted bin, spodziewaj się, że alokator później ustawi `*(TARGET) = unsorted_chunks(av)`. Obie wartości zwykle są duże i mogą wystarczyć do zmiany semantyki rozmiaru/limitów w celach, które tylko sprawdzają "duże". + +Szkielet pseudokodu: +```c +// 64-bit glibc 2.35–2.38 style layout (tcache bypass via large sizes) +void *A = malloc(0x5000); +void *B = malloc(0x5000); +void *C = malloc(0x5000); // guard + +// overflow from A into B’s metadata (prev_size/size/.../bk). You must control B->bk. +*(size_t *)((char*)B - 0x8) = (size_t)(TARGET - 0x10); // write fake bk + +free(B); // triggers *(TARGET) = B (unsorted-bin insertion write) +``` +> [!NOTE] +> • Jeśli nie możesz ominąć tcache za pomocą rozmiaru, zapełnij tcache bin dla wybranego rozmiaru (7 frees) przed zwolnieniem uszkodzonego chunku, aby free trafił do unsorted. +> • Jeśli program natychmiast przerywa wykonanie przy następnej alokacji z powodu unsorted-bin checks, sprawdź ponownie, czy `victim->fd` wciąż równa się bin head oraz czy twój `TARGET` zawiera dokładny pointer do `victim` po pierwszym zapisie. + +## Unsorted Bin Infoleak Attack + +To w istocie bardzo podstawowa koncepcja. Chunks w unsorted bin będą zawierać wskaźniki. Pierwszy chunk w unsorted bin będzie faktycznie miał linki **`fd`** i **`bk`** **wskazujące na część main arena (Glibc)**.\ +W związku z tym, jeśli możesz **umieścić chunk w unsorted bin i go odczytać** (use after free) lub **alokować go ponownie bez nadpisania przynajmniej jednego z wskaźników**, a następnie go **odczytać**, możesz uzyskać **Glibc info leak**. + +Podobny [**atak użyty w tym writeupie**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html) polegał na nadużyciu struktury 4 chunków (A, B, C i D — D służy tylko do zapobieżenia konsolidacji z top chunk), więc null byte overflow w B został użyty, by sprawić, że C będzie wskazywać, że B jest nieużywany. Dodatkowo w B pole `prev_size` zostało zmodyfikowane tak, że rozmiar zamiast być rozmiarem B był A+B.\ +Następnie C został zwolniony i skonsolidowany z A+B (ale B nadal był używany). Przydzielono nowy chunk o rozmiarze A, a potem do B zapisano libc leaked addresses, skąd następnie je odczytano. + +## Referencje i inne przykłady - [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap**](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żliwe było uzyskanie flagi, a PIE nie jest włączone. -- Możliwe jest generowanie kawałków o dowolnych rozmiarach i 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 niezorganizowany koszyk i zmodyfikuje wartość zmiennej globalnej, umożliwiając uzyskanie flagi. +- Celem jest nadpisanie zmiennej globalnej wartością większą niż 4869, aby możliwe było zdobycie flagi i PIE nie jest włączone. +- Możliwe jest wygenerowanie chunków o dowolnych rozmiarach i istnieje heap overflow o żądanym rozmiarze. +- Atak zaczyna się od stworzenia 3 chunków: chunk0 do nadużycia overflow, chunk1 który ma być overflowowany oraz chunk2, aby top chunk nie skonsolidował poprzednich. +- Następnie chunk1 jest zwalniany, a chunk0 jest overflowowany tak, że `bk` wskazywane przez chunk1 pokazuje na: `bk = magic - 0x10` +- Potem alokowany jest chunk3 o tym samym rozmiarze co chunk1, co wywoła unsorted bin attack i zmodyfikuje wartość zmiennej globalnej, umożliwiając zdobycie flagi. - [**https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html**](https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html) -- Funkcja scalania jest podatna, ponieważ jeśli oba przekazane indeksy są takie same, to zostanie ponownie alokowana i następnie zwolniona, ale zwracając 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 scalania 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 alokować tylko rozmiary większe niż **`global_max_fast`**, więc żaden szybki koszyk nie jest używany, zostanie użyty atak na niezorganizowany koszyk, aby nadpisać zmienną globalną `global_max_fast`. -- Następnie możliwe jest wywołanie funkcji edytowania 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 niezorganizowany koszyk**, nadpisując `global_max_fast`, co jest bardzo dużą wartością, umożliwiając teraz 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`**: +- Funkcja merge jest podatna, ponieważ jeśli oba przekazane indeksy są takie same, to następuje realloc na tym indeksie, a potem jego free, ale zwracany jest pointer do tej zwolnionej regionu, który można wykorzystać. +- W związku z tym **tworzone są 2 chunky**: **chunk0**, który zostanie scalony sam ze sobą, oraz chunk1 żeby zapobiec konsolidacji z top chunk. Następnie **merge function jest wywoływana dla chunk0** dwukrotnie, co spowoduje use after free. +- Potem wywoływana jest funkcja **`view`** z indeksem 2 (który odpowiada use after free chunkowi), co spowoduje **leak libc address**. +- Ponieważ binarka ma zabezpieczenia, które pozwalają mallocować tylko rozmiary większe niż **`global_max_fast`**, więc nie używa się fastbinów — zastosowany zostanie unsorted bin attack, aby nadpisać zmienną globalną `global_max_fast`. +- Następnie można wywołać funkcję edycji z indeksem 2 (pointer use after free) i nadpisać wskaźnik `bk`, aby wskazywał na `p64(global_max_fast-0x10)`. Potem stworzenie nowego chunku użyje wcześniej skompromitowanego adresu free (0x20) i **wywoła unsorted bin attack**, nadpisując `global_max_fast` na bardzo dużą wartość, co pozwoli teraz tworzyć chunki w fast binach. +- Teraz wykonywany jest **fast bin attack**: +- Najpierw odkryto, że można pracować z fast **chunkami o rozmiarze 200** w lokalizacji **`__free_hook`**: -
gef➤ p &__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
@@ -58,16 +116,20 @@ gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
0x7ff1e9e6076f : 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 scalania 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 edytowania 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.
+- Jeśli uda się uzyskać fast chunk o rozmiarze 0x200 w tej lokalizacji, będzie można nadpisać wskaźnik funkcji, który zostanie wykonany.
+- W tym celu tworzony jest nowy chunk o rozmiarze `0xfc` i funkcja merge jest wywoływana z tym wskaźnikiem dwukrotnie — w ten sposób uzyskujemy pointer do zwolnionego chunku o rozmiarze `0xfc*2 = 0x1f8` w fast binie.
+- Potem wywoływana jest funkcja edycji na tym chunku, aby zmodyfikować adres **`fd`** tego fast binu tak, aby wskazywał na poprzedni **`__free_hook`**.
+- Następnie alokowany jest chunk o rozmiarze `0x1f8`, aby pobrać ze fast binu poprzedni nieużyteczny chunk, a potem kolejny chunk o rozmiarze `0x1f8`, aby otrzymać fast bin chunk w **`__free_hook`**, który jest nadpisywany adresem funkcji **`system`**.
+- I w końcu chunk zawierający string `/bin/sh\x00` jest zwalniany przez wywołanie funkcji delete, wywołując **`__free_hook`**, które teraz wskazuje na system z `/bin/sh\x00` jako parametrem.
- **CTF** [**https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html)
-- Inny przykład nadużywania przepełnienia 1B do konsolidacji kawałków w niezorganizowanym koszyku i uzyskania wycieku informacji libc, a następnie przeprowadzenia ataku na szybki koszyk w celu nadpisania wskaźnika malloc z adresem jednego gadżetu.
+- Kolejny przykład nadużycia 1B overflow, aby skonsolidować chunki w unsorted bin i uzyskać libc infoleak, a następnie przeprowadzić fast bin attack w celu nadpisania malloc hook adresem one gadget.
- [**Robot Factory. BlackHat MEA CTF 2022**](https://7rocky.github.io/en/ctf/other/blackhat-ctf/robot-factory/)
-- Możemy alokować tylko kawałki o rozmiarze większym niż `0x100`.
-- Nadpisanie `global_max_fast` za pomocą ataku na niezorganizowany 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`.
+- Możemy alokować tylko chunki o rozmiarze większym niż `0x100`.
+- Nadpisanie `global_max_fast` przy użyciu Unsorted Bin attack (działa 1/16 razy z powodu ASLR, ponieważ trzeba zmodyfikować 12 bitów, ale trzeba zmodyfikować 16 bitów).
+- Fast Bin attack, aby zmodyfikować globalną tablicę chunków. To daje arbitralny read/write primitive, co pozwala na modyfikację GOT i ustawienie pewnej funkcji, by wskazywała na `system`.
+## References
+
+- Glibc malloc unsorted-bin integrity checks (example in 2.33 source): https://elixir.bootlin.com/glibc/glibc-2.33/source/malloc/malloc.c
+- `global_max_fast` and related definitions in modern glibc (2.39): https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c
{{#include ../../banners/hacktricks-training.md}}