BROP - Blind Return Oriented Programming

Support HackTricks

Basic Information

Ο στόχος αυτής της επίθεσης είναι να μπορέσουμε να καταχραστούμε ένα ROP μέσω μιας υπερχείλισης buffer χωρίς καμία πληροφορία για το ευάλωτο δυαδικό αρχείο. Αυτή η επίθεση βασίζεται στο εξής σενάριο:

  • Μια ευπάθεια στο stack και γνώση του πώς να την ενεργοποιήσουμε.

  • Μια εφαρμογή server που επανεκκινείται μετά από μια κατάρρευση.

Attack

1. Βρείτε την ευάλωτη απόσταση στέλνοντας έναν επιπλέον χαρακτήρα μέχρι να ανιχνευθεί μια δυσλειτουργία του server

2. Brute-force canary για να το διαρρεύσετε

3. Brute-force αποθηκευμένες διευθύνσεις RBP και RIP στο stack για να τις διαρρεύσετε

Μπορείτε να βρείτε περισσότερες πληροφορίες για αυτές τις διαδικασίες εδώ (BF Forked & Threaded Stack Canaries) και εδώ (BF Addresses in the Stack).

4. Βρείτε το gadget STOP

Αυτό το gadget επιτρέπει βασικά να επιβεβαιωθεί ότι κάτι ενδιαφέρον εκτελέστηκε από το gadget ROP επειδή η εκτέλεση δεν κατέρρευσε. Συνήθως, αυτό το gadget θα είναι κάτι που σταματά την εκτέλεση και είναι τοποθετημένο στο τέλος της αλυσίδας ROP όταν αναζητάμε gadgets ROP για να επιβεβαιώσουμε ότι εκτελέστηκε ένα συγκεκριμένο gadget ROP.

5. Βρείτε το gadget BROP

Αυτή η τεχνική χρησιμοποιεί το ret2csu gadget. Και αυτό συμβαίνει επειδή αν αποκτήσετε πρόσβαση σε αυτό το gadget στη μέση κάποιων εντολών, αποκτάτε gadgets για να ελέγξετε rsi και rdi:

Αυτά θα είναι τα gadgets:

  • pop rsi; pop r15; ret

  • pop rdi; ret

Παρατηρήστε πώς με αυτά τα gadgets είναι δυνατό να ελέγξετε 2 παραμέτρους μιας συνάρτησης που θα καλέσετε.

Επίσης, παρατηρήστε ότι το gadget ret2csu έχει μια πολύ μοναδική υπογραφή επειδή θα popάρει 6 καταχωρητές από το stack. Έτσι, στέλνοντας μια αλυσίδα όπως:

'A' * offset + canary + rbp + ADDR + 0xdead * 6 + STOP

Αν το STOP εκτελείται, αυτό σημαίνει βασικά ότι χρησιμοποιήθηκε μια διεύθυνση που popάρει 6 καταχωρητές από το stack. Ή ότι η διεύθυνση που χρησιμοποιήθηκε ήταν επίσης μια διεύθυνση STOP.

Για να αφαιρεθεί αυτή η τελευταία επιλογή, εκτελείται μια νέα αλυσίδα όπως η εξής και δεν πρέπει να εκτελεί το gadget STOP για να επιβεβαιώσει ότι το προηγούμενο popάρισε 6 καταχωρητές:

'A' * offset + canary + rbp + ADDR

Γνωρίζοντας τη διεύθυνση του gadget ret2csu, είναι δυνατό να συμπεράνουμε τη διεύθυνση των gadgets για να ελέγξουμε rsi και rdi.

6. Βρείτε το PLT

Ο πίνακας PLT μπορεί να αναζητηθεί από 0x400000 ή από τη διευθυνση RIP που διαρρέει από το stack (αν χρησιμοποιείται PIE). Οι καταχωρήσεις του πίνακα είναι χωρισμένες κατά 16B (0x10B), και όταν καλείται μια συνάρτηση, ο server δεν καταρρέει ακόμη και αν οι παράμετροι δεν είναι σωστοί. Επίσης, η έλεγχος της διεύθυνσης μιας καταχώρησης στο PLT + 6B επίσης δεν καταρρέει καθώς είναι ο πρώτος κώδικας που εκτελείται.

Επομένως, είναι δυνατό να βρείτε τον πίνακα PLT ελέγχοντας τις εξής συμπεριφορές:

  • 'A' * offset + canary + rbp + ADDR + STOP -> καμία κατάρρευση

  • 'A' * offset + canary + rbp + (ADDR + 0x6) + STOP -> καμία κατάρρευση

  • 'A' * offset + canary + rbp + (ADDR + 0x10) + STOP -> καμία κατάρρευση

7. Εύρεση strcmp

Η συνάρτηση strcmp ρυθμίζει τον καταχωρητή rdx στο μήκος της συμβολοσειράς που συγκρίνεται. Σημειώστε ότι rdx είναι η τρίτη παράμετρος και πρέπει να είναι μεγαλύτερη από 0 προκειμένου να χρησιμοποιήσουμε αργότερα το write για να διαρρεύσουμε το πρόγραμμα.

Είναι δυνατό να βρείτε την τοποθεσία της strcmp στον PLT με βάση τη συμπεριφορά της χρησιμοποιώντας το γεγονός ότι μπορούμε τώρα να ελέγξουμε τις 2 πρώτες παραμέτρους των συναρτήσεων:

  • strcmp(<non read addr>, <non read addr>) -> κατάρρευση

  • strcmp(<non read addr>, <read addr>) -> κατάρρευση

  • strcmp(<read addr>, <non read addr>) -> κατάρρευση

  • strcmp(<read addr>, <read addr>) -> καμία κατάρρευση

Είναι δυνατό να ελέγξετε αυτό καλώντας κάθε καταχώρηση του πίνακα PLT ή χρησιμοποιώντας τη PLT slow path που βασικά συνίσταται στο να καλείτε μια καταχώρηση στον πίνακα PLT + 0xb (η οποία καλεί το dlresolve) ακολουθούμενη στο stack από τον αριθμό καταχώρησης που θέλετε να ελέγξετε (ξεκινώντας από το μηδέν) για να σαρώσετε όλες τις καταχωρήσεις PLT από την πρώτη:

  • strcmp(<non read addr>, <read addr>) -> κατάρρευση

  • b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP -> Θα καταρρεύσει

  • strcmp(<read addr>, <non read addr>) -> κατάρρευση

  • b'A' * offset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP

  • strcmp(<read addr>, <read addr>) -> καμία κατάρρευση

  • b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP

Θυμηθείτε ότι:

  • BROP + 0x7 δείχνει στο pop RSI; pop R15; ret;

  • BROP + 0x9 δείχνει στο pop RDI; ret;

  • PLT + 0xb δείχνει σε μια κλήση στο dl_resolve.

Αφού βρείτε το strcmp, είναι δυνατό να ρυθμίσετε το rdx σε μια τιμή μεγαλύτερη από 0.

Σημειώστε ότι συνήθως το rdx θα φιλοξενεί ήδη μια τιμή μεγαλύτερη από 0, οπότε αυτό το βήμα μπορεί να μην είναι απαραίτητο.

8. Εύρεση Write ή ισοδύναμου

Τέλος, χρειάζεται ένα gadget που να εξάγει δεδομένα προκειμένου να εξάγει το δυαδικό αρχείο. Και σε αυτό το σημείο είναι δυνατό να ελέγξετε 2 παραμέτρους και να ρυθμίσετε το rdx μεγαλύτερο από 0.

Υπάρχουν 3 κοινές συναρτήσεις που θα μπορούσαν να καταχραστούν για αυτό:

  • puts(data)

  • dprintf(fd, data)

  • write(fd, data, len(data)

Ωστόσο, το αρχικό έγγραφο αναφέρει μόνο τη συνάρτηση write, οπότε ας μιλήσουμε γι' αυτήν:

Το τρέχον πρόβλημα είναι ότι δεν γνωρίζουμε πού βρίσκεται η συνάρτηση write μέσα στον PLT και δεν γνωρίζουμε έναν αριθμό fd για να στείλουμε τα δεδομένα στη σύνδεσή μας.

Ωστόσο, γνωρίζουμε πού είναι ο πίνακας PLT και είναι δυνατό να βρούμε τη write με βάση τη συμπεριφορά της. Και μπορούμε να δημιουργήσουμε πολλές συνδέσεις με τον server και να χρησιμοποιήσουμε έναν υψηλό FD ελπίζοντας ότι θα ταιριάζει με κάποιες από τις συνδέσεις μας.

Υπογραφές συμπεριφοράς για να βρείτε αυτές τις συναρτήσεις:

  • 'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP -> Αν εκτυπωθούν δεδομένα, τότε βρέθηκε η puts

  • 'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP -> Αν εκτυπωθούν δεδομένα, τότε βρέθηκε η dprintf

  • 'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + (RIP + 0x1) + p64(0x0) + (PLT + 0xb ) + p64(STRCMP ENTRY) + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP -> Αν εκτυπωθούν δεδομένα, τότε βρέθηκε η write

Automatic Exploitation

References

Support HackTricks

Last updated