Ret2esp / Ret2reg
Ret2esp
Ponieważ ESP (Wskaźnik stosu) zawsze wskazuje na górę stosu, ta technika polega na zastąpieniu EIP (Wskaźnik instrukcji) adresem instrukcji jmp esp
lub call esp
. Dzięki temu shellcode jest umieszczany bezpośrednio po nadpisanej wartości EIP. Gdy instrukcja ret
zostanie wykonana, ESP wskazuje na następny adres, dokładnie tam, gdzie przechowywany jest shellcode.
Jeśli Randomizacja Układu Przestrzeni Adresowej (ASLR) nie jest włączona w systemie Windows lub Linux, można użyć instrukcji jmp esp
lub call esp
znalezionych w bibliotekach współdzielonych. Jednakże, przy aktywnym ASLR, konieczne może być poszukiwanie tych instrukcji w samym programie podatnym (i być może trzeba będzie pokonać PIE).
Co więcej, umożliwienie umieszczenia shellcode po nadpisaniu EIP, a nie w środku stosu, zapewnia, że żadne instrukcje push
lub pop
wykonane podczas działania funkcji nie będą ingerować w shellcode. Taka ingerencja mogłaby wystąpić, gdyby shellcode został umieszczony w środku stosu funkcji.
Brak miejsca
Jeśli brakuje miejsca do zapisania po nadpisaniu RIP (może to być tylko kilka bajtów), napisz początkowy jmp
shellcode, na przykład:
I zapisz shellcode na początku stosu.
Przykład
Możesz znaleźć przykład tej techniki w https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp z końcowym exploit'em jak:
Możesz zobaczyć kolejny przykład tej techniki na https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html. Istnieje tu przepełnienie bufora bez włączonego NX, używany jest gadżet do zmniejszenia adresu $esp
a następnie jmp esp;
aby przejść do kodu powłoki:
Ret2reg
Podobnie, jeśli znamy funkcję zwracającą adres, w którym przechowywany jest kod powłoki, możemy wykorzystać instrukcje call eax
lub jmp eax
(znane jako technika ret2eax), oferującą inną metodę wykonania naszego kodu powłoki. Podobnie jak eax, dowolny inny rejestr zawierający interesujący adres może być użyty (ret2reg).
Przykład
Możesz znaleźć kilka przykładów tutaj:
strcpy
będzie przechowywane weax
adresie bufora, w którym przechowywany jest kod powłoki ieax
nie jest nadpisywany, więc można użyćret2eax
.
ARM64
Ret2sp
W ARM64 nie ma instrukcji pozwalających na skok do rejestru SP. Możliwe jest znalezienie gadżetu, który przenosi sp do rejestru, a następnie skacze do tego rejestru, ale w bibliotece libc mojego kali nie znalazłem takiego gadżetu:
Jedynymi, które odkryłem, zmieniłyby wartość rejestru, do którego został skopiowany sp przed skokiem do niego (co sprawiłoby, że stałby się bezużyteczny):
Ret2reg
Jeśli rejestr ma interesujący adres, można do niego skoczyć, znajdując odpowiednią instrukcję. Możesz użyć czegoś w stylu:
W ARM64 to x0
przechowuje wartość zwracaną przez funkcję, więc może się zdarzyć, że x0 przechowuje adres bufora kontrolowanego przez użytkownika z shellcodem do wykonania.
Przykładowy kod:
Sprawdzając rozkład funkcji, można zauważyć, że adres bufora (podatnego na przepełnienie buforu i kontrolowanego przez użytkownika) jest przechowywany w x0
przed powrotem z przepełnienia buforu:
Można również znaleźć gadżet br x0
w funkcji do_stuff
:
Wykorzystamy ten gadżet, aby do niego przeskoczyć, ponieważ binarny plik jest kompilowany BEZ PIE. Korzystając z wzorca, można zauważyć, że przesunięcie przepełnienia buforu wynosi 80, więc exploit będzie:
Jeśli zamiast fgets
zostało użyte coś w stylu read
, byłoby możliwe obejście PIE również przez nadpisanie tylko ostatnich 2 bajtów adresu powrotu aby powrócić do instrukcji br x0;
bez konieczności znajomości pełnego adresu.
Z fgets
to nie działa, ponieważ dodaje bajt null (0x00) na końcu.
Protections
NX: Jeśli stos nie jest wykonawczy, to nie pomoże, ponieważ musimy umieścić shellcode na stosie i skoczyć, aby go wykonać.
References
Last updated