Libc Protections
Last updated
Last updated
Dowiedz się i ćwicz hakowanie AWS:HackTricks Training AWS Red Team Expert (ARTE) Dowiedz się i ćwicz hakowanie GCP: HackTricks Training GCP Red Team Expert (GRTE)
Malloc alokuje pamięć w grupach 8 bajtów (32-bit) lub 16 bajtów (64-bit). Oznacza to, że koniec chunków w systemach 32-bitowych powinien być wyrównany do 0x8, a w systemach 64-bitowych do 0x0. Funkcja bezpieczeństwa sprawdza, czy każdy chunk jest poprawnie wyrównany na tych konkretnych lokalizacjach przed użyciem wskaźnika z pojemnika.
Egzekwowanie wyrównania chunków w systemach 64-bitowych znacząco zwiększa bezpieczeństwo Malloc poprzez ograniczenie umieszczania fałszywych chunków tylko na 1 z każdych 16 adresów. Sprawia to, że wysiłki eksploatacyjne są bardziej skomplikowane, zwłaszcza w scenariuszach, gdzie użytkownik ma ograniczoną kontrolę nad wartościami wejściowymi, co sprawia, że ataki są bardziej złożone i trudniejsze do wykonania pomyślnie.
Atak Fastbin na __malloc_hook
Nowe zasady wyrównania w Malloc uniemożliwiają również klasyczny atak polegający na manipulowaniu __malloc_hook
. Wcześniej atakujący mogli manipulować rozmiarami chunków, aby nadpisać ten wskaźnik funkcji i uzyskać wykonanie kodu. Teraz surowe wymagania co do wyrównania zapewniają, że takie manipulacje nie są już możliwe, zamykając powszechną drogę eksploatacji i zwiększając ogólne bezpieczeństwo.
Mieszanie Wskaźników to zabezpieczenie używane do ochrony wskaźników Fd fastbinów i tcache w operacjach zarządzania pamięcią. Ta technika pomaga zapobiegać pewnym rodzajom taktyk eksploatacji pamięci, zwłaszcza tym, które nie wymagają wycieku informacji o pamięci lub manipulowania lokalizacjami pamięci bezpośrednio względem znanych pozycji (nadpisywanie względne).
Rdzeniem tej techniki jest wzór obfuskacji:
Nowy_Wskaźnik = (L >> 12) XOR P
L to Lokalizacja Przechowywania wskaźnika.
P to rzeczywisty Wskaźnik Fd fastbinu/tcache.
Powód przesunięcia bitowego lokalizacji przechowywania (L) o 12 bitów w prawo przed operacją XOR jest kluczowy. Ta manipulacja adresuje podatność wynikającą z deterministycznej natury najmniej znaczących 12 bitów adresów pamięci, które zazwyczaj są przewidywalne ze względu na ograniczenia architektury systemu. Przesunięcie bitów przenosi przewidywalną część z równania, zwiększając losowość nowego, zmieszanego wskaźnika i tym samym zabezpieczając przed atakami polegającymi na przewidywalności tych bitów.
Ten zmieszany wskaźnik wykorzystuje istniejącą losowość zapewnianą przez Losową Układankę Przestrzeni Adresowej (ASLR), która losowo ustala adresy używane przez programy, aby utrudnić atakującym przewidywanie układu pamięci procesu.
Demiksowanie wskaźnika w celu odzyskania oryginalnego adresu polega na użyciu tej samej operacji XOR. Tutaj zmieszany wskaźnik jest traktowany jako P w formule, a gdy jest XORowany z niezmienioną lokalizacją przechowywania (L), odsłania oryginalny wskaźnik. Ta symetria w mieszaniu i demiksowaniu zapewnia, że system może efektywnie kodować i dekodować wskaźniki bez znaczącego narzutu, jednocześnie znacznie zwiększając bezpieczeństwo przed atakami manipulującymi wskaźnikami pamięci.
Mieszanie wskaźników ma na celu zapobieganie nadpisywaniu częściowego i pełnego wskaźnika w stercie, co stanowi znaczące wzmocnienie bezpieczeństwa. Ta funkcja wpływa na techniki eksploatacji w kilku aspektach:
Zapobieganie Nadpisywaniu Wskaźników Względnych Bye Byte: Wcześniej atakujący mogli zmienić część wskaźnika, aby przekierować chunki sterty na inne lokalizacje bez znajomości dokładnych adresów, technika widoczna w eksploacie House of Roman bez wycieku sterty. Dzięki mieszaniu wskaźników, takie nadpisywanie względne bez wycieku sterty teraz wymaga ataku brute force, drastycznie zmniejszając szanse na sukces.
Zwiększenie Trudności Ataków na Tcache Bin/Fastbin: Powszechne ataki, które nadpisują wskaźniki funkcji (jak __malloc_hook
) poprzez manipulowanie wpisami fastbinów lub tcache, są utrudnione. Na przykład atak może polegać na wycieku adresu LibC, zwolnieniu chunka do tcache binu, a następnie nadpisaniu wskaźnika Fd, aby przekierować go do __malloc_hook
w celu wykonania arbitralnego kodu. Dzięki mieszaniu wskaźników, te wskaźniki muszą być poprawnie zmieszane, wymagając wycieku sterty do dokładnej manipulacji, podnosząc tym samym barierę eksploatacji.
Wymaganie Wycieku Sterty w Lokacjach Spoza Sterty: Utworzenie fałszywego chunka w obszarach spoza sterty (jak stos, sekcja .bss lub PLT/GOT) teraz również wymaga wycieku sterty ze względu na konieczność mieszania wskaźników. To zwiększa złożoność eksploatowania tych obszarów, podobnie jak wymaganie manipulowania adresami LibC.
Wyciek Adresów Sterty Staje Się Trudniejszy: Mieszanie wskaźników ogranicza przydatność wskaźników Fd w fastbinach i tcache binach jako źródeł wycieków adresów sterty. Jednak wskaźniki w nieuporządkowanych, małych i dużych binach pozostają niezmieszane, nadal nadają się do wycieków adresów. Ten przesunięcie zmusza atakujących do eksplorowania tych binów w poszukiwaniu informacji podatnych na eksploatację, chociaż niektóre techniki mogą nadal pozwalać na demiksowanie wskaźników przed wyciekiem, choć z ograniczeniami.
Dla lepszego wyjaśnienia procesu sprawdź oryginalny post tutaj.
Wzór używany do mieszania i demiksowania wskaźników to:
Nowy_Wskaźnik = (L >> 12) XOR P
Gdzie L to lokalizacja przechowywania, a P to wskaźnik Fd. Przesunięcie L w prawo o 12 bitów pozwala uzyskać najbardziej znaczące bity P, ze względu na naturę operacji XOR, która zwraca 0, gdy bity są XORowane ze sobą.
Kluczowe Kroki w Algorytmie:
Początkowe Wycieki Najbardziej Znaczących Bitów: Poprzez XORowanie przesuniętego L z P, efektywnie otrzymujesz 12 najbardziej znaczących bitów P, ponieważ przesunięta część L będzie zerem, pozostawiając niezmienione bity odpowiadające P.
Odzyskiwanie Bitów Wskaźnika: Ponieważ XOR jest odwracalny, znajomość wyniku i jednego z operandów pozwala obliczyć drugi operand. Ta właściwość jest wykorzystywana do wydedukowania całego zestawu bitów dla P, poprzez sukcesywne XORowanie znanych zestawów bitów z częściami zmieszanego wskaźnika.
Iteracyjne Demiksowanie: Proces jest powtarzany, za każdym razem używając nowo odkrytych bitów P z poprzedniego kroku do dekodowania kolejnego segmentu zmieszanego wskaźnika, aż wszystkie bity zostaną odzyskane.
Obsługa Deterministycznych Bitów: Ostatnie 12 bitów L są tracone z powodu przesunięcia, ale są one deterministyczne i mogą być odtworzone po procesie.
Możesz znaleźć implementację tego algorytmu tutaj: https://github.com/mdulin2/mangle
Ochrona wskaźnika to technika zabezpieczeń wykorzystywana w bibliotece glibc do ochrony przechowywanych wskaźników funkcji, zwłaszcza tych zarejestrowanych przez wywołania biblioteczne, takie jak atexit()
. Ochrona ta polega na przemieszaniu wskaźników poprzez operację XOR z sekretem przechowywanym w danych wątku (fs:0x30
) i zastosowaniu bitowej rotacji. Mechanizm ten ma na celu zapobieganie atakom polegającym na przejęciu kontroli poprzez nadpisanie wskaźników funkcji.
Zrozumienie operacji ochrony wskaźnika: Przemieszanie wskaźników jest wykonywane za pomocą makra PTR_MANGLE
, które wykonuje operację XOR na wskaźniku z 64-bitowym tajnym kluczem, a następnie wykonuje lewą rotację o 0x11 bitów. Operacja odwrotna do odzyskania pierwotnego wskaźnika jest obsługiwana przez PTR_DEMANGLE
.
Strategia ataku: Atak opiera się na podejściu znanych tekstów jawnie, gdzie atakujący musi znać zarówno oryginalną, jak i przemieszaną wersję wskaźnika, aby wydedukować użyty do przemieszania sekret.
Wykorzystanie znanych tekstów jawnie:
Identyfikacja stałych wskaźników funkcji: Poprzez analizę kodu źródłowego glibc lub zainicjowanych tabel wskaźników funkcji (np. __libc_pthread_functions
), atakujący może znaleźć przewidywalne wskaźniki funkcji.
Obliczanie sekretu: Korzystając z znanego wskaźnika funkcji, takiego jak __pthread_attr_destroy
i jego przemieszanej wersji z tabeli wskaźników funkcji, sekret można obliczyć poprzez odwrócenie rotacji (prawej rotacji) przemieszanego wskaźnika, a następnie wykonanie operacji XOR z adresem funkcji.
Alternatywne teksty jawnie: Atakujący może również eksperymentować z przemieszaniem wskaźników znanymi wartościami, takimi jak 0 lub -1, aby sprawdzić, czy powodują one rozpoznawalne wzorce w pamięci, potencjalnie ujawniając sekret, gdy te wzorce zostaną znalezione w zrzutach pamięci.
Zastosowanie praktyczne: Po obliczeniu sekretu atakujący może manipulować wskaźnikami w kontrolowany sposób, w zasadzie omijając ochronę wskaźnika w aplikacji wielowątkowej z znajomością adresu bazowego libc i możliwością odczytu dowolnych lokalizacji pamięci.