mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
49 lines
5.7 KiB
Markdown
49 lines
5.7 KiB
Markdown
# 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}}
|