Return-to-user to najłatwiejsza technika eksploatacji jądra, porównywalna z podstawowymi technikami opisanymi wcześniej, które pozwoliły nam wykonywać kody powłoki z włączonym NX i wyłączonym ASLR. Głównym celem ret2usr jest nadpisanie rejestru RIP i przejęcie przepływu wykonywania w przestrzeni jądra w celu podniesienia uprawnień bieżącego procesu za pomocą funkcji jądra:
commit_creds(prepare_kernel_cred(0)). Działa to w przypadku bieżącego procesu przestrzeni użytkownika, ponieważ commit_creds instaluje nowe poświadczenia, które mają zostać przypisane do bieżącego zadania. Teraz, gdy mamy nadpisanie RIP, nasza strategia jest następująca:
- Znajdź adresy dla prepare_kernel_cred i commit_creds w /proc/kallsyms. Te adresy pozostaną takie same po ponownym uruchomieniu, ponieważ KASLR jest wyłączony.
- Zamiast wykonywać kod powłoki, napisz funkcję z wbudowanym asemblerem, która wykona commit_creds(prepare_kernel_cred(0)).
- Wróć do przestrzeni użytkownika, używając kodów operacji swapgs i iretq.
Napiszmy teraz, skompilujmy i wykonajmy nasz exploit. Dostarczymy i udokumentujemy pełne źródło, ale kolejne sekcje będą zawierać tylko niezbędne poprawki kodu wymagane do ominięcia każdej techniki łagodzenia exploitów. Pełne źródło tego laboratorium można znaleźć w następującej ścieżce: ~/GHHv6/ch12/shared/exploit1/exploit.c.
W (1) nasz exploit wykonuje kod, aby podnieść uprawnienia naszego zadania w trybie jądra. Po wykonaniu tej czynności musimy przełączyć się z powrotem do przestrzeni użytkownika i wykonać system(“/bin/sh”)(2). Pierwszym problemem, z jakim się mierzymy, jest to, że aby powrócić do przestrzeni użytkownika, instrukcja Interrupt Return (iretq) musi mieć poprawne wartości w rejestrach CS, RFLAGS, SP, SS i RIP, a rejestry te są modyfikowane w obu trybach. Rozwiązaniem jest użycie tego inline assembly do zapisania rejestrów przed przejściem do trybu jądra i przywrócenie ich ze stosu przed wywołaniem instrukcji iretq. W (3) nadpisujemy RIP adresem funkcji escalate_privileges, która zawiera kod niezbędny do wykonania commit_creds(prepare_kernel_cred(0)), używamy instrukcji swapgs do zamiany rejestru GS na wartość w jednym z rejestrów specyficznych dla modelu (MSR), przywracamy rejestry CS, RFLAGS, SP, SS i na koniec kierujemy RIP do funkcji powłoki przed wywołaniem iretq. Zanim przejdziemy dalej, uzyskajmy adres funkcji prepare_kernel_cred (4) i commit_creds (5) w naszym systemie docelowym i zmodyfikujmy skrypt tymi adresami:
Po zmodyfikowaniu linii (4) i (5) adresem prepare_kernel_cred i commit_creds, utworzymy teraz naszą tablicę unsigned long (6) i zainicjujemy ją zerami. Pamiętaj, że odkryliśmy, że RIP może zostać nadpisany na bajcie 24, a ponieważ każdy element naszej tablicy unsigned long ma długość 8 bajtów, będziemy musieli zapisać adres funkcji escalate_privileges (3) na trzecim (24 / 8) elemencie naszej tablicy payload. Na koniec otwieramy /proc/ghh i zapisujemy nasz payload (8). Teraz, gdy wszystko jest gotowe, skompilujmy nasz exploit. Jego uruchomienie powinno spowodować wykonanie powłoki /bin/sh z podwyższonymi uprawnieniami użytkownika root:
Świetnie! Teraz włączmy Stack Canaries, abyśmy mogli zrozumieć, jak to działa i dowiedzieć się, jak to ominąć w tym scenariuszu