Leaking libc address with ROP
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Find overflow offset
Find POP_RDI
gadget, PUTS_PLT
and MAIN
gadgets
Użyj poprzednich gadgetów, aby wyciekować adres pamięci funkcji puts lub innej funkcji libc i znaleźć wersję libc (pobierz ją)
Z biblioteką, oblicz ROP i wykorzystaj to
Ten samouczek będzie wykorzystywał kod/binary zaproponowany w tym samouczku: https://tasteofsecurity.com/security/ret2libc-unknown-libc/ Inne przydatne samouczki: https://made0x78.com/bseries-ret2libc/, https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html
Filename: vuln.c
Pobierz exploit i umieść go w tym samym katalogu co podatny binarny plik, a następnie przekaż potrzebne dane do skryptu:
Leaking libc - templateSzablon potrzebuje offsetu przed kontynuowaniem exploitacji. Jeśli jakikolwiek zostanie podany, wykona niezbędny kod, aby go znaleźć (domyślnie OFFSET = ""
):
Wykonaj python template.py
, a konsola GDB zostanie otwarta z programem, który uległ awarii. Wewnątrz tej konsoli GDB wykonaj x/wx $rsp
, aby uzyskać bajty, które miały nadpisać RIP. Na koniec uzyskaj offset używając konsoli python:
Po znalezieniu offsetu (w tym przypadku 40) zmień zmienną OFFSET w szablonie, używając tej wartości.
OFFSET = "A" * 40
Innym sposobem byłoby użycie: pattern create 1000
-- wykonaj do ret -- pattern seach $rsp
z GEF.
Teraz musimy znaleźć gadżety ROP w binarnym pliku. Te gadżety ROP będą przydatne do wywołania puts
, aby znaleźć używaną libc, a później do uruchomienia ostatecznego exploit.
PUTS_PLT
jest potrzebny do wywołania funkcji puts.
MAIN_PLT
jest potrzebny do ponownego wywołania funkcji main po jednej interakcji, aby wykorzystać przepełnienie ponownie (nieskończone rundy eksploatacji). Jest używany na końcu każdego ROP, aby ponownie wywołać program.
POP_RDI jest potrzebny do przekazania parametru do wywoływanej funkcji.
W tym kroku nie musisz nic wykonywać, ponieważ wszystko zostanie znalezione przez pwntools podczas wykonania.
Teraz czas, aby znaleźć, która wersja biblioteki libc jest używana. Aby to zrobić, zamierzamy wyciek adresu w pamięci funkcji puts
, a następnie zamierzamy przeszukać, w której wersji biblioteki znajduje się wersja puts w tym adresie.
Aby to zrobić, najważniejsza linia wykonanego kodu to:
To wyśle kilka bajtów, aż nadpisanie RIP będzie możliwe: OFFSET
.
Następnie ustawi adres gadżetu POP_RDI
, aby następny adres (FUNC_GOT
) został zapisany w rejestrze RDI. Dzieje się tak, ponieważ chcemy wywołać puts, przekazując mu adres PUTS_GOT
, ponieważ adres w pamięci funkcji puts jest zapisany w adresie wskazywanym przez PUTS_GOT
.
Po tym zostanie wywołany PUTS_PLT
(z PUTS_GOT
wewnątrz RDI), aby puts odczytał zawartość wewnątrz PUTS_GOT
(adres funkcji puts w pamięci) i wydrukował go.
Na koniec funkcja main jest wywoływana ponownie, abyśmy mogli ponownie wykorzystać przepełnienie.
W ten sposób oszukaliśmy funkcję puts, aby wydrukowała adres w pamięci funkcji puts (która znajduje się w bibliotece libc). Teraz, gdy mamy ten adres, możemy sprawdzić, która wersja libc jest używana.
Ponieważ eksploatujemy lokalny binarny plik, nie ma potrzeby ustalania, która wersja libc jest używana (po prostu znajdź bibliotekę w /lib/x86_64-linux-gnu/libc.so.6
).
Jednak w przypadku zdalnego eksploatującego wyjaśnię tutaj, jak można to znaleźć:
Możesz sprawdzić, która biblioteka jest używana na stronie: https://libc.blukat.me/ Pozwoli to również pobrać odkrytą wersję libc
Możesz również zrobić:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
To zajmie trochę czasu, bądź cierpliwy. Aby to zadziałało, potrzebujemy:
Nazwa symbolu libc: puts
Wyciekniony adres libc: 0x7ff629878690
Możemy ustalić, która libc jest najprawdopodobniej używana.
Otrzymujemy 2 dopasowania (powinieneś spróbować drugiego, jeśli pierwsze nie działa). Pobierz pierwsze:
Skopiuj libc z libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
do naszego katalogu roboczego.
Na tym etapie powinniśmy znać używaną bibliotekę libc. Ponieważ wykorzystujemy lokalny binarny plik, użyję tylko: /lib/x86_64-linux-gnu/libc.so.6
Na początku template.py
zmień zmienną libc na: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Ustaw ścieżkę do biblioteki, gdy ją znamy
Podając ścieżkę do biblioteki libc, reszta eksploitu zostanie automatycznie obliczona.
Wewnątrz funkcji get_addr
zostanie obliczony adres bazowy libc:
Zauważ, że ostateczny adres bazy libc musi kończyć się na 00. Jeśli tak nie jest, mogłeś wyciekować niepoprawną bibliotekę.
Następnie adres do funkcji system
oraz adres do ciągu "/bin/sh" będą obliczane na podstawie adresu bazy libc i podanej biblioteki libc.
Na koniec przygotowywany jest exploit do wykonania /bin/sh:
Let's explain this final ROP.
Ostatni ROP (rop1
) zakończył się ponownym wywołaniem funkcji main, więc możemy ponownie wykorzystać przepełnienie (dlatego OFFSET
jest tutaj znowu). Następnie chcemy wywołać POP_RDI
, wskazując na adres "/bin/sh" (BINSH
) i wywołać funkcję system (SYSTEM
), ponieważ adres "/bin/sh" zostanie przekazany jako parametr.
Na koniec adres funkcji exit jest wywoływany, aby proces ładnie zakończył działanie i nie został wygenerowany żaden alert.
W ten sposób exploit uruchomi powłokę _/bin/sh_**.**
Możesz również użyć ONE_GADGET , aby uzyskać powłokę zamiast używać system i "/bin/sh". ONE_GADGET znajdzie w bibliotece libc sposób na uzyskanie powłoki, używając tylko jednego adresu ROP.
Jednak zazwyczaj istnieją pewne ograniczenia, najczęstsze i łatwe do ominięcia to [rsp+0x30] == NULL
. Ponieważ kontrolujesz wartości wewnątrz RSP, musisz tylko wysłać kilka dodatkowych wartości NULL, aby ograniczenie zostało ominięte.
Możesz znaleźć szablon do wykorzystania tej podatności tutaj:
Leaking libc - templateJeśli symbol "main" nie istnieje. Wtedy możesz znaleźć, gdzie znajduje się główny kod:
i ustaw adres ręcznie:
Jeśli binarny plik nie używa Puts, powinieneś sprawdzić, czy używa
sh: 1: %s%s%s%s%s%s%s%s: nie znaleziono
Jeśli znajdziesz ten błąd po stworzeniu wszystkich exploitów: sh: 1: %s%s%s%s%s%s%s%s: nie znaleziono
Spróbuj odjąć 64 bajty od adresu "/bin/sh":
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)