Heap Overflow

Wesprzyj HackTricks

Podstawowe informacje

Przepełnienie sterty jest podobne do przepełnienia stosu, ale występuje w stercie. Oznacza to, że pewna przestrzeń została zarezerwowana w stercie do przechowywania danych i przechowywane dane były większe niż zarezerwowana przestrzeń.

W przypadku przepełnień stosu wiemy, że niektóre rejestry, takie jak wskaźnik instrukcji lub ramka stosu, zostaną przywrócone ze stosu i możliwe jest ich nadużycie. W przypadku przepełnień sterty domyślnie nie ma przechowywanych żadnych wrażliwych informacji w kawałku sterty, który może zostać przepełniony. Jednak mogą to być wrażliwe informacje lub wskaźniki, więc krytyczność tej podatności zależy od tego, które dane mogą zostać nadpisane i jak atakujący mógłby to wykorzystać.

Aby znaleźć przesunięcia przepełnień, można użyć tych samych wzorców co w przepełnieniach stosu.

Przepełnienia stosu vs przepełnienia sterty

W przypadku przepełnień stosu układ i dane, które będą obecne na stosie w momencie wywołania podatności, są dość niezawodne. Wynika to z faktu, że stos jest liniowy, zawsze zwiększający się w kolizyjnej pamięci, w konkretnych miejscach działania programu pamięć stosu zazwyczaj przechowuje podobny rodzaj danych i ma określoną strukturę z pewnymi wskaźnikami na końcu części stosu używanej przez każdą funkcję.

Jednak w przypadku przepełnień sterty używana pamięć nie jest liniowa, ale przydzielane kawałki są zazwyczaj w oddzielonych pozycjach pamięci (nie obok siebie) ze względu na kosze i strefy oddzielające alokacje według rozmiaru oraz dlatego, że poprzednio zwolniona pamięć jest używana przed alokacją nowych kawałków. Jest trudno określić obiekt, który będzie kolidować z podatnym na przepełnienie obiektem. Dlatego, gdy znajdowane jest przepełnienie sterty, konieczne jest znalezienie niezawodnego sposobu, aby pożądany obiekt był następny w pamięci od tego, który może zostać przepełniony.

Jedną z technik używanych do tego jest Grooming sterty, która jest używana na przykład w tym poście. W poście wyjaśniono, że gdy w jądrze iOS strefa wyczerpie pamięć do przechowywania kawałków pamięci, rozszerza ją o stronę jądra, a ta strona jest dzielona na kawałki o oczekiwanych rozmiarach, które będą używane w kolejności (do wersji iOS 9.2, następnie te kawałki są używane w losowy sposób, aby utrudnić eksploatację tych ataków).

Dlatego w poprzednim poście, gdzie występuje przepełnienie sterty, aby wymusić, aby obiekt przepełniony kolidował z obiektem ofiary, kilka kallocs jest wymuszanych przez kilka wątków, aby upewnić się, że wszystkie wolne kawałki są wypełnione i że zostaje utworzona nowa strona.

Aby wymusić to wypełnienie obiektami o określonym rozmiarze, przydział poza linią związanego z portem mach iOS jest idealnym kandydatem. Poprzez dostosowanie rozmiaru wiadomości możliwe jest dokładne określenie rozmiaru alokacji kalloc, a gdy odpowiadający port mach zostanie zniszczony, odpowiadająca alokacja zostanie natychmiast zwolniona z powrotem do kfree.

Następnie niektóre z tych miejsc mogą być zwolnione. Lista zwolnionych elementów kalloc.4096 zwalnia elementy w kolejności ostatni przydzielony - pierwszy zwolniony, co w zasadzie oznacza, że jeśli niektóre miejsca są zwalniane i exploit próbuje przydzielić kilka obiektów ofiary, próbując przydzielić obiekt podatny na przepełnienie, jest prawdopodobne, że ten obiekt będzie następowany przez obiekt ofiary.

Przykładowa biblioteka libc

Na tej stronie można znaleźć podstawową emulację przepełnienia sterty, która pokazuje, jak nadpisanie poprzedniego bitu w użyciu następnego kawałka i pozycja poprzedniego rozmiaru umożliwia skonsolidowanie użytego kawałka (poprzez sprawienie, że myśli, że jest nieużywany) i następnie ponowne go alokować, co pozwala na nadpisanie danych używanych w innym wskaźniku.

Inny przykład z protostar heap 0 pokazuje bardzo podstawowy przykład CTF, w którym przepełnienie sterty może być wykorzystane do wywołania funkcji zwycięzcy i uzyskania flagi.

W przykładzie protostar heap 1 można zobaczyć, jak nadużywając przepełnienia bufora, można nadpisać w sąsiednim kawałku adres, gdzie dowolne dane od użytkownika zostaną zapisane.

Przykład ARM64

Na stronie https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/ znajdziesz przykład przepełnienia sterty, gdzie polecenie, które ma zostać wykonane, jest przechowywane w następnym kawałku po przepełnionym kawałku. Dlatego możliwe jest zmodyfikowanie wykonywanego polecenia poprzez nadpisanie go prostym exploitem.

python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt

Inne przykłady

  • Wykorzystujemy podatność na przepełnienie liczby całkowitej, aby uzyskać przepełnienie sterty.

  • Szkodzimy wskaźniki do funkcji wewnątrz struct przekroczonego fragmentu, aby ustawić funkcję taką jak system i uzyskać wykonanie kodu.

Wesprzyj HackTricks

Last updated