DDexec / EverythingExec
Last updated
Last updated
Ucz się i praktykuj Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Ucz się i praktykuj Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
W systemie Linux, aby uruchomić program, musi on istnieć jako plik, musi być dostępny w jakiś sposób poprzez hierarchię systemu plików (tak działa execve()
). Ten plik może znajdować się na dysku lub w pamięci RAM (tmpfs, memfd), ale potrzebujesz ścieżki do niego. To sprawia, że bardzo łatwo kontrolować, co jest uruchamiane w systemie Linux, ułatwia wykrywanie zagrożeń i narzędzi atakujących lub zapobieganie próbom uruchomienia czegokolwiek przez nich (np. nie zezwalając nieuprzywilejowanym użytkownikom na umieszczanie plików wykonywalnych w dowolnym miejscu).
Ale ta technika ma na celu zmianę tego wszystkiego. Jeśli nie możesz uruchomić procesu, którego chcesz... to przejmujesz już istniejący.
Ta technika pozwala ci obejść powszechne techniki ochronne, takie jak tylko do odczytu, noexec, białe listy nazw plików, białe listy hashy...
Ostateczny skrypt zależy od następujących narzędzi, aby działał, muszą być one dostępne w atakowanym systemie (domyślnie znajdziesz je wszędzie):
Jeśli jesteś w stanie dowolnie modyfikować pamięć procesu, możesz go przejąć. Można to wykorzystać do przejęcia już istniejącego procesu i zastąpienia go innym programem. Możemy osiągnąć to albo używając wywołania systemowego ptrace()
(co wymaga możliwości wykonywania wywołań systemowych lub dostępności gdb w systemie) albo, co ciekawsze, zapisując do /proc/$pid/mem
.
Plik /proc/$pid/mem
jest jedno do jednego odwzorowaniem całej przestrzeni adresowej procesu (np. od 0x0000000000000000
do 0x7ffffffffffff000
w x86-64). Oznacza to, że odczytanie lub zapisanie do tego pliku na przesunięciu x
jest takie samo jak odczytanie lub modyfikowanie zawartości pod adresem wirtualnym x
.
Teraz mamy cztery podstawowe problemy do rozwiązania:
Ogólnie rzecz biorąc, tylko root i właściciel pliku mogą go modyfikować.
ASLR.
Jeśli spróbujemy odczytać lub zapisać do adresu spoza zmapowanej przestrzeni adresowej programu, otrzymamy błąd wejścia/wyjścia.
Te problemy mają rozwiązania, które, mimo że nie są idealne, są dobre:
Większość interpreterów powłoki pozwala na utworzenie deskryptorów plików, które zostaną dziedziczone przez procesy potomne. Możemy utworzyć deskryptor wskazujący na plik mem
powłoki z uprawnieniami do zapisu... więc procesy potomne korzystające z tego deskryptora będą mogły modyfikować pamięć powłoki.
ASLR nie stanowi nawet problemu, możemy sprawdzić plik maps
powłoki lub inny z procfs, aby uzyskać informacje o przestrzeni adresowej procesu.
Musimy więc wykonać lseek()
na pliku. Z poziomu powłoki nie można tego zrobić chyba że używając niesławnej komendy dd
.
Kroki są stosunkowo proste i nie wymagają żadnego rodzaju specjalistycznej wiedzy, aby je zrozumieć:
Analizujemy binarnik, który chcemy uruchomić oraz loader, aby dowiedzieć się, jakie odwzorowania potrzebują. Następnie tworzymy "shell"code, który będzie wykonywał, ogólnie mówiąc, te same kroki, które jądro wykonuje przy każdym wywołaniu execve()
:
Tworzymy wspomniane odwzorowania.
Wczytujemy do nich binaria.
Ustawiamy uprawnienia.
Na koniec inicjalizujemy stos argumentami dla programu i umieszczamy wektor pomocniczy (potrzebny przez loader).
Skaczemy do loadera i pozwalamy mu zrobić resztę (załaduje biblioteki potrzebne przez program).
Pobieramy z pliku syscall
adres, do którego proces powróci po wywołaniu systemowym, który wykonuje.
Nadpisujemy to miejsce, które będzie wykonywalne, naszym shellcodem (poprzez mem
możemy modyfikować strony, które nie są zapisywalne).
Przekazujemy program, który chcemy uruchomić do stdin procesu (będzie odczytany przez wspomniany "shell"code).
W tym momencie loader ma za zadanie załadować niezbędne biblioteki dla naszego programu i przejść do niego.
Sprawdź narzędzie na https://github.com/arget13/DDexec
Istnieje kilka alternatyw do dd
, jedną z nich jest tail
, obecnie domyślny program używany do lseek()
przez plik mem
(który był jedynym celem użycia dd
). Wspomniane alternatywy to:
Ustawiając zmienną SEEKER
możesz zmienić użytego poszukiwacza, np.:
Jeśli znajdziesz innego ważnego poszukiwacza, który nie został zaimplementowany w skrypcie, nadal możesz go użyć, ustawiając zmienną SEEKER_ARGS
:
Zablokuj to, EDR-y.
Naucz się i praktykuj Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Naucz się i praktykuj Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)