# Heap Overflow {{#include ../../banners/hacktricks-training.md}} ## Podstawowe informacje Heap overflow jest jak [**stack overflow**](../stack-overflow/index.html), ale w stercie. Zasadniczo oznacza to, że pewna przestrzeń została zarezerwowana w stercie do przechowywania danych, a **przechowywane dane były większe niż zarezerwowana przestrzeń.** W przypadku stack overflow wiemy, że niektóre rejestry, takie jak wskaźnik instrukcji czy ramka stosu, będą przywracane ze stosu i można to wykorzystać. W przypadku heap overflow **nie ma żadnych wrażliwych informacji przechowywanych domyślnie** w kawałku sterty, który może być przepełniony. Jednak mogą to być wrażliwe informacje lub wskaźniki, więc **krytyczność** tej podatności **zależy** od **tego, jakie dane mogą być nadpisane** i jak atakujący może to wykorzystać. > [!TIP] > Aby znaleźć przesunięcia przepełnienia, możesz użyć tych samych wzorców, co w przypadku [**stack overflow**](../stack-overflow/index.html#finding-stack-overflows-offsets). ### Stack Overflows vs Heap Overflows W przypadku stack overflow układ i dane, które będą obecne na stosie w momencie, gdy podatność może zostać wyzwolona, są dość wiarygodne. Dzieje się tak, ponieważ stos jest liniowy, zawsze rośnie w kolidującej pamięci, w **konkretnych miejscach działania programu pamięć stosu zazwyczaj przechowuje podobny rodzaj danych** i ma pewną specyficzną strukturę z pewnymi wskaźnikami na końcu części stosu używanej przez każdą funkcję. Jednak w przypadku heap overflow używana pamięć nie jest liniowa, ale **alokowane kawałki są zazwyczaj w oddzielnych pozycjach pamięci** (nie jeden obok drugiego) z powodu **koszyków i stref** oddzielających alokacje według rozmiaru oraz dlatego, że **wcześniej zwolniona pamięć jest używana** przed alokowaniem nowych kawałków. **Trudno jest wiedzieć, który obiekt będzie kolidował z tym, który jest podatny** na heap overflow. Dlatego, gdy znajdzie się heap overflow, konieczne jest znalezienie **wiarygodnego sposobu, aby pożądany obiekt był następny w pamięci** od tego, który może być przepełniony. Jedną z technik używanych do tego jest **Heap Grooming**, która jest używana na przykład [**w tym poście**](https://azeria-labs.com/grooming-the-ios-kernel-heap/). W poście wyjaśniono, jak w jądrze iOS, gdy strefa kończy się pamięcią do przechowywania kawałków pamięci, rozszerza ją o stronę jądra, a ta strona jest dzielona na kawałki oczekiwanych rozmiarów, które będą używane w kolejności (do wersji iOS 9.2, potem te kawałki są używane w sposób losowy, aby utrudnić wykorzystanie tych ataków). Dlatego w poprzednim poście, w którym występuje heap overflow, aby wymusić kolizję przepełnionego obiektu z obiektem ofiary, kilka **`kallocs` jest wymuszanych przez kilka wątków, aby spróbować zapewnić, że wszystkie wolne kawałki są wypełnione i że nowa strona jest tworzona**. Aby wymusić to wypełnienie obiektami o określonym rozmiarze, **alokacja poza linią związana z portem mach iOS** jest idealnym kandydatem. Poprzez skonstruowanie rozmiaru wiadomości, można dokładnie określić rozmiar alokacji `kalloc`, a gdy odpowiedni port mach zostanie zniszczony, odpowiednia alokacja zostanie natychmiast zwolniona do `kfree`. Następnie niektóre z tych miejsc mogą być **zwolnione**. Lista wolnych elementów **`kalloc.4096` zwalnia elementy w kolejności ostatni wchodzi, pierwszy wychodzi**, co zasadniczo oznacza, że jeśli niektóre miejsca są zwolnione, a exploit próbuje alokować kilka obiektów ofiar, podczas gdy próbuje alokować obiekt podatny na przepełnienie, prawdopodobne jest, że ten obiekt będzie następował po obiekcie ofiary. ### Przykład libc [**Na tej stronie**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html) można znaleźć podstawową emulację heap overflow, która pokazuje, jak nadpisanie bitu prev in use następnego kawałka i pozycji prev size pozwala na **konsolidację używanego kawałka** (sprawiając, że myśli, że jest nieużywany) i **następnie ponowne przydzielenie go**, będąc w stanie nadpisać dane, które są używane w innym wskaźniku. Inny przykład z [**protostar heap 0**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap0/index.html) pokazuje bardzo podstawowy przykład CTF, w którym **heap overflow** może być wykorzystany do wywołania funkcji zwycięzcy, aby **zdobyć flagę**. W przykładzie [**protostar heap 1**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap1/index.html) można zobaczyć, jak wykorzystując przepełnienie bufora, można **nadpisać w pobliskim kawałku adres**, gdzie **dane użytkownika** będą zapisywane. ### Przykład ARM64 Na stronie [https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/](https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/) można znaleźć przykład heap overflow, w którym polecenie, które ma być wykonane, jest przechowywane w następnym kawałku z przepełnionego kawałka. Tak więc, możliwe jest modyfikowanie wykonywanego polecenia, nadpisując je prostym exploitem, takim jak: ```bash python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt ``` ### Inne przykłady - [**Auth-or-out. Hack The Box**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/auth-or-out/) - Wykorzystujemy podatność na przepełnienie całkowite, aby uzyskać przepełnienie sterty. - Korumpujemy wskaźniki do funkcji wewnątrz `struct` przepełnionego kawałka, aby ustawić funkcję taką jak `system` i uzyskać wykonanie kodu. {{#include ../../banners/hacktricks-training.md}}