<summary><strong>Naucz się hakować AWS od zera do bohatera z</strong><ahref="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
* Jeśli chcesz zobaczyć swoją **firmę reklamowaną w HackTricks** lub **pobrać HackTricks w formacie PDF**, sprawdź [**PLANY SUBSKRYPCYJNE**](https://github.com/sponsors/carlospolop)!
* **Dołącz do** 💬 [**grupy Discord**](https://discord.gg/hRep4RUj7f) lub [**grupy telegramowej**](https://t.me/peass) lub **śledź** nas na **Twitterze** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
Aby sprawdzić, czy wywołania systemowe są wykonywane poprawnie, należy skompilować poprzedni program, a wywołania systemowe powinny pojawić się w **strace ./SKOMPILOWANY\_PROGRAM**
Podczas tworzenia shellcode'u można zastosować sztuczkę. Pierwsza instrukcja to skok do wywołania. Wywołanie wykonuje oryginalny kod i dodatkowo umieszcza EIP na stosie. Po instrukcji call umieszczamy potrzebny nam ciąg znaków, dzięki czemu za pomocą tego EIP możemy wskazać na ciąg znaków i kontynuować wykonywanie kodu.
Polega na małym kodzie, który przeszukuje strony pamięci powiązane z procesem w poszukiwaniu tam przechowywanej shellcode (szuka jakiegoś podpisu umieszczonego w shellcode). Przydatne w przypadkach, gdy mamy tylko niewielką przestrzeń do wstrzyknięcia kodu.
Polegają na zaszyfrowanych shellach, które mają małe kody deszyfrujące i skaczące do nich, używając sztuczki Call-Pop, oto **przykład zaszyfrowanego szyfru Cezara**:
Analizując jak jest budowany stos nowego procesu w systemie Linux, można opracować exploit w taki sposób, że program zostanie uruchomiony w środowisku, w którym jedyną zmienną jest shellcode. Adres tej zmiennej można obliczyć jako: addr = 0xbfffffff - 4 - strlen(NOMBRE\_ejecutable\_completo) - strlen(shellcode)
Funkcja **sprintf** przesuwa sformatowany łańcuch do zmiennej. Dlatego można nadużyć formatowania łańcucha, aby spowodować przepełnienie bufora w zmiennej, do której jest kopiowana zawartość.\
Na przykład ładunek `%.44xAAAA` zapisze 44B+"AAAA" w zmiennej, co może spowodować przepełnienie bufora.
Funkcja **`atexit()`** to funkcja, do której przekazywane są inne funkcje jako parametry. Te funkcje zostaną wykonane podczas wywołania **`exit()`** lub powrotu z funkcji **main**.\
Jeśli można **zmodyfikować** adres którejś z tych funkcji, aby wskazywał na shellcode na przykład, można przejąć kontrolę nad procesem, ale obecnie jest to bardziej skomplikowane.\
Obecnie **adresy funkcji** do wykonania są **ukryte** za kilkoma strukturami, a ostatecznie adres, na który wskazują, nie jest adresem funkcji, lecz jest **zaszyfrowany za pomocą operacji XOR** i przesunięć z **losowym kluczem**. Dlatego obecnie ten wektor ataku nie jest zbyt przydatny, przynajmniej na architekturach x86 i x64\_86.\
Funkcja **szyfrowania** to **`PTR_MANGLE`**. **Inne architektury** takie jak m68k, mips32, mips64, aarch64, arm, hppa... **nie implementują funkcji szyfrowania**, ponieważ **zwracają to samo**, co otrzymały jako dane wejściowe. Dlatego te architektury mogą być podatne na ten wektor ataku.
Problem polega na tym, że EIP i ESP są przekazywane przez funkcję **`PTR_MANGLE`**, więc **architektury podatne na ten atak są takie same jak wyżej**.\
Są one przydatne do obsługi błędów lub przerwań.\
Jednak z tego, co przeczytałem, inne rejestry nie są chronione, **więc jeśli wewnątrz wywoływanej funkcji występuje `call ebx`, `call esi` lub `call edi`**, można przejąć kontrolę. Można także zmodyfikować EBP, aby zmienić ESP.
Każdy obiekt klasy ma **VPtr**, który jest **wskaźnikiem** do tablicy swojej klasy. VPtr jest częścią nagłówka każdego obiektu, więc jeśli osiągnięto **nadpisanie** VPtr, można je **zmienić**, aby wskazywało na metodę zastępczą, dzięki czemu wykonanie funkcji przejdzie do shellcode.
Wywołania niektórych funkcji niewłaściwych są przechwytywane przez inne bezpieczne funkcje. Nie jest to standaryzowane. (tylko dla x86, nie dla kompilacji z -fomit-frame-pointer, nie dla statycznych kompilacji, nie wszystkie niewłaściwe funkcje stają się bezpieczne, a LD\_PRELOAD nie działa dla binarnych z ustawionym suid).
Polega na ładowaniu współdzielonych bibliotek od 0x00000000 do 0x00ffffff, aby zawsze był bajt 0x00. Jednakże to nie zatrzymuje praktycznie żadnego ataku, a tym bardziej w little endian.
Polega na wykonaniu ROP w taki sposób, że wywoływana jest funkcja strcpy@plt (z plt), a następnie wskazuje się na wpis w GOT i kopiowany jest pierwszy bajt funkcji, do której chcemy się odwołać (system()). Następnie to samo jest wykonywane wskazując na GOT+1 i kopiując 2. bajt system()... Na końcu wywoływany jest zapisany adres w GOT, który będzie system()
W "size" są bity wskazujące: czy poprzedni kawałek jest używany, czy kawałek został przydzielony za pomocą mmap() i czy kawałek należy do głównego obszaru.
Jeśli przy zwalnianiu kawałka którykolwiek z sąsiednich kawałków jest wolny, są one łączone za pomocą makra unlink() i nowy, większy kawałek jest przekazywany do frontlink() w celu wstawienia go do odpowiedniego binu.
BK->fd = FD -> \*(\&shellcode + 8) = (&\_\_dtor\_end\_\_ - 12) —> Spowoduje to zapisanie 4 bajtów od 8 bajtu shellcode, dlatego pierwsza instrukcja shellcode musi być skokiem, aby ominąć to i przejść do nops prowadzących do reszty shellcode.
Następnie po shellcode dodajemy wypełnienie do osiągnięcia pola prev\_size i size następnego kawałka. W tych miejscach umieszczamy 0xfffffff0 (aby nadpisać prev\_size i oznaczyć go jako wolny) oraz “-4” (0xfffffffc) w size (aby podczas sprawdzania w 3. kawałku, czy 2. był wolny, w rzeczywistości przejdzie do zmodyfikowanego prev\_size, który wskaże, że jest wolny) -> Dlatego gdy free() sprawdzi, przejdzie do size 3. kawałka, ale w rzeczywistości przejdzie do 2. - 4 i uzna, że 2. kawałek jest wolny. Następnie zostanie wywołane **unlink()**.
Podczas wywoływania unlink() użyje pierwszych danych z drugiego kawałka jako P->fd, więc tam zostanie umieszczony adres, który chcesz nadpisać - 12 (ponieważ w FD->bk dodaje 12 do adresu przechowywanego w FD). Następnie w tym adresie zostanie wprowadzony drugi adres znaleziony w drugim kawałku, który będzie interesujący dla nas jako adres shellcode (fałszywy P->bk).
W rezultacie program będzie myślał, że "a" jest wolny i w binie, więc wywoła unlink(), aby go odłączyć. Jednakże, ponieważ nagłówek PREV_SIZE wynosi -4. Będzie myślał, że kawałek "a" zaczyna się naprawdę w b+4. Innymi słowy, wywoła unlink() na kawałek, który zaczyna się w b+4, więc w b+12 będzie wskaźnik "fd", a w b+16 będzie wskaźnik "bk".
Frontlink jest wywoływany, gdy coś jest zwalniane i żaden z sąsiednich kawałków nie jest wolny, wtedy nie jest wywoływane unlink(), ale jest wywoływane bezpośrednio frontlink().
W ten sposób, nadpisując w dwóch mallocach w sposób niekontrolowany i w jednym kontrolowanym, który jest zwalniany tylko raz, możemy przeprowadzić exploit.
Jeśli chcemy ponownie użyć jednego, nie ma problemu. Jeśli chcemy użyć innego, zostanie przypisane to samo miejsce, więc mamy fałszywe wskaźniki "fd" i "bk" z danymi, które zapisze poprzednia rezerwacja.
Wystarczy jedno wywołanie free(), aby spowodować wykonanie arbitralnego kodu. Warto znaleźć drugi kawałek, który może zostać przepełniony przez poprzedni i zwolniony.
W \[1] sprawdzany jest rozmiar pola bitowego NON_MAIN_ARENA, który można zmienić, aby sprawdzenie zwróciło true i wywołało heap_for_ptr(), które wykonuje operację and na "mem", ustawiając na 0 2,5 najmniej znaczących bajtów (w naszym przypadku z 0x0804a000 robi 0x08000000) i uzyskuje dostęp do 0x08000000->ar_ptr (jak do struct heap_info)
W ten sposób, jeśli możemy kontrolować kawałek na przykład w 0x0804a000 i kawałek zostanie zwolniony w **0x081002a0**, możemy dotrzeć do adresu 0x08100000 i zapisać, co chcemy, na przykład **0x0804a000**. Gdy ten drugi kawałek zostanie zwolniony, heap_for_ptr(ptr)->ar_ptr zwróci to, co napisaliśmy w 0x08100000 (ponieważ stosuje się do 0x081002a0 operację and, którą widzieliśmy wcześniej, i stąd wyciąga wartość pierwszych 4 bajtów, ar_ptr)
Dlatego jeśli w av->bins\[2] zapiszemy wartość \_\_DTOR_END\_\_-12, w ostatniej instrukcji zostanie zapisane w \_\_DTOR_END\_\_ adres drugiego kawałka.
W miejscu, gdzie znajduje się adres drugiego kawałka z ostatnimi 5 zerami, należy zapisać adres tego pierwszego kawałka, aby heap_for_ptr() myślał, że ar_ptr znajduje się na początku pierwszego kawałka i z niego wyciągnął av->bins\[2]
W drugim fragmencie, dzięki pierwszemu, nadpisujemy prev\_size za pomocą jump 0x0c i size czymś, aby aktywować -> NON\_MAIN\_ARENA
W ten sposób zostanie wywołane \_int\_free(TROZO1, TROZO2) i będzie kontynuować instrukcje, aby zapisać w \_\_DTOR\_END\_\_ adres prev\_size z TROZO2, który skoczy do shellcode.
Ta technika nie jest już stosowana, ponieważ zastosowano prawie ten sam patch co dla unlink. Sprawdzane jest, czy nowe miejsce, do którego się odwołujemy, również odwołuje się do nas.
W ten sposób, jeśli umieścimy "fb" w adresie funkcji w GOT, pod tym adresem umieszczony zostanie adres nadpisanego fragmentu. Wymaga to, aby arena była blisko adresów dtors. Dokładniej mówiąc, av->max\_fast musi znajdować się pod adresem, który zamierzamy nadpisać.
Dodatkowo musi być spełniony warunek, że fragment sąsiadujący z uwolnionym musi być większy niż 8 -> Ponieważ powiedzieliśmy, że rozmiar uwolnionego fragmentu to 8, w tym fałszywym fragmencie wystarczy umieścić rozmiar większy niż 8 (ponieważ shellcode będzie w uwolnionym fragmencie, na początku trzeba umieścić jump, który trafi w nops).
Ze względu na zera z \_DTOR\_END\_ i niewiele adresów w GOT, żaden z tych obszarów nie nadaje się do nadpisania, zobaczmy więc, jak zastosować fastbin do ataku na stos.
Dodatkowo musi być spełniony warunek, że fragment sąsiadujący z uwolnionym musi być większy niż 8 -> Ponieważ powiedzieliśmy, że rozmiar uwolnionego fragmentu to 16, w tym fałszywym fragmencie wystarczy umieścić rozmiar większy niż 8 (ponieważ shellcode będzie w uwolnionym fragmencie, na początku trzeba umieścić jump, który trafi w nops, które znajdują się po polu size nowego fałszywego fragmentu).
W tym przypadku chcemy mieć wskaźnik do malloc, który może być modyfikowany przez atakującego (np. wskaźnik znajduje się na stosie podczas możliwego przepełnienia zmiennej).
W ten sposób możemy sprawić, że ten wskaźnik wskazuje dokądkolwiek. Jednak nie każde miejsce jest ważne, rozmiar fałszywego fragmentu musi być mniejszy niż av->max\_fast i bardziej konkretne, równy rozmiarowi żądanemu w przyszłym wywołaniu malloc()+8. Dlatego jeśli wiemy, że po tym podatnym wskaźniku następuje wywołanie malloc(40), rozmiar fałszywego fragmentu musi wynosić 48.
Na przykład, jeśli program pyta użytkownika o liczbę, możemy wprowadzić 48 i skierować modyfikowalny wskaźnik malloc na następne 4 bajty (które mogą należeć do EBP, dzięki czemu 48 pozostaje z tyłu, jakby to była nagłówek size). Ponadto, adres ptr-4+48 musi spełniać kilka warunków (w tym przypadku ptr=EBP), czyli 8 <ptr-4+48<av->system\_mem.
Jeśli to się spełni, gdy zostanie wywołane kolejne malloc, które powiedzieliśmy, że jest malloc(40), zostanie mu przypisany adres EBP. Jeśli atakujący może również kontrolować to, co jest zapisywane w tym malloc, może nadpisać zarówno EBP, jak i EIP dowolnym adresem.
Prawdopodobnie dlatego, że gdy zostanie zwolnione free(), zostanie zapisane, że w adresie wskazującym na EBP stosu znajduje się fragment o idealnym rozmiarze dla nowego malloc(), który chce zarezerwować, więc przypisuje mu ten adres.
Najpierw nadpisujemy rozmiar fragmentu wilderness bardzo dużą wartością (0xffffffff), dzięki czemu każde żądanie pamięci wystarczająco duże będzie obsługiwane w \_int\_malloc() bez konieczności rozszerzania sterty.
Victim przechwytuje adres bieżącego fragmentu wilderness (aktualne av->top), a remainder to dokładnie suma tego adresu i liczby bajtów żądanych przez malloc(). Dlatego jeśli \&EIP-8 znajduje się pod adresem 0xbffff224, a av->top zawiera 0x080c2788, to ilość, którą musimy zarezerwować w kontrolowanym malloc, aby av->top wskazywał na $EIP-8 dla następnego malloc(), wynosi:
Ważne jest, aby rozmiar nowego fragmentu wilderness był większy niż żądanie ostatniego malloc(). Innymi słowy, jeśli wilderness wskazuje na \&EIP-8, rozmiar zostanie dokładnie w polu EBP stosu.
Uwolnione fragmenty są umieszczane w bin w zależności od ich rozmiaru. Ale zanim zostaną umieszczone, są przechowywane w unsorted bins. Gdy fragment zostanie zwolniony, nie jest natychmiast umieszczany w swoim binie, ale pozostaje w unsorted bins. Następnie, jeśli zostanie zarezerwowany nowy fragment i poprzedni zwolniony może mu służyć, zostanie mu zwrócony, ale jeśli zostanie zarezerwowany większy, zwolniony fragment z unsorted bins zostanie umieszczony w odpowiednim binie.
bin->bk = bck; Przedostatni kawałek staje się ostatnim, jeśli bck wskazuje na stos do następnego zarezerwowanego kawałka, zostanie przypisany ten adres.
Zarezerwowanie dwóch malloc, aby można było przeprowadzić przepełnienie pierwszego po zwolnieniu drugiego i umieszczeniu go w swoim binie (czyli zarezerwowano malloc większy niż drugi kawałek przed przepełnieniem)
Celem jest to, że jeśli możemy przeprowadzić przepełnienie na stercie, która ma zwolniony kawałek poniżej i w swoim binie, możemy zmienić wskaźnik bk. Jeśli zmienimy wskaźnik bk i ten kawałek stanie się pierwszym na liście bin i zostanie zarezerwowany, bin zostanie oszukany i powiemy mu, że ostatni kawałek na liście (następny do zaoferowania) znajduje się pod fałszywym adresem, który podaliśmy (na przykład na stosie lub GOT). W rezultacie, jeśli zostanie ponownie zarezerwowany inny kawałek, a atakujący ma uprawnienia do niego, zostanie mu przydzielony kawałek na żądanej pozycji i będzie mógł w nią pisać.
Po zwolnieniu zmodyfikowanego kawałka konieczne jest zarezerwowanie kawałka większego od zwolnionego, aby zmodyfikowany kawałek wyszedł z nieuporządkowanych binów i został umieszczony w swoim binie.
Następnie bin musi poczekać, aż malloc() zostanie wywołane wystarczająco wiele razy, aby ponownie użyć zmodyfikowanego bina i oszukać bin, sprawiając, że uwierzy, że następny kawałek znajduje się pod fałszywym adresem. Następnie zostanie przydzielony kawałek, który nas interesuje.
Aby wykorzystać podatność jak najszybciej, idealne jest: zarezerwowanie podatnego kawałka, zarezerwowanie kawałka, który zostanie zmodyfikowany, zwolnienie tego kawałka, zarezerwowanie kawałka większego od tego, który zostanie zmodyfikowany, zmodyfikowanie kawałka (podatność), zarezerwowanie kawałka o takim samym rozmiarze co naruszony i zarezerwowanie drugiego kawałka o takim samym rozmiarze, który będzie wskazywał na wybrany adres.
Aby zabezpieczyć się przed tym atakiem, używa się standardowej weryfikacji, czy kawałek "nie" jest fałszywy: sprawdza się, czy bck->fd wskazuje na victim. Innymi słowy, w naszym przypadku, jeśli wskaźnik fd\* fałszywego kawałka wskazuje na victim na stosie. Aby ominąć to zabezpieczenie, atakujący musiałby być w stanie w jakiś sposób (prawdopodobnie przez stos) zapisać w odpowiednim miejscu adres victim. W ten sposób kawałek wydaje się być prawdziwy.
Atak jest podobny do poprzedniego, czyli trzeba zmienić wskaźnik bk i wymagane są wszystkie te wywołania malloc(), ale dodatkowo trzeba zmienić rozmiar zmodyfikowanego kawałka tak, aby ten rozmiar - nb był <MINSIZE.
Polega na zarezerwowaniu jak największej ilości pamięci dla sterty i wypełnieniu jej poduszką z nops zakończoną shellcodem. Dodatkowo jako poduszkę używa się 0x0c. Następnie próbuje się skoczyć do adresu 0x0c0c0c0c, więc jeśli jakaś adres zostanie nadpisany tymi nopsami, skok zostanie wykonany tam. Podstawową taktyką jest zarezerwowanie jak największej ilości pamięci, aby sprawdzić, czy jakiś wskaźnik zostanie nadpisany, i skok do 0x0c0c0c0c w nadziei, że tam będą nopsy.
Polega na ustawieniu pamięci poprzez rezerwacje i zwolnienia w taki sposób, aby między wolnymi kawałkami pozostały zarezerwowane kawałki. Bufor do przepełnienia zostanie umieszczony w jednym z tych kawałków.
<summary><strong>Naucz się hakować AWS od zera do bohatera z</strong><ahref="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
* Jeśli chcesz zobaczyć swoją **firmę reklamowaną w HackTricks** lub **pobrać HackTricks w formacie PDF**, sprawdź [**PLANY SUBSKRYPCYJNE**](https://github.com/sponsors/carlospolop)!
* Kup [**oficjalne gadżety PEASS & HackTricks**](https://peass.creator-spring.com)
* **Dołącz do** 💬 [**Grupy Discord**](https://discord.gg/hRep4RUj7f) lub [**grupy telegramowej**](https://t.me/peass) lub **śledź** nas na **Twitterze** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.