ROP - Return Oriented Programing
Βασικές Πληροφορίες
Η Προγραμματισμένη Επιστροφή (ROP) είναι μια προηγμένη τεχνική εκμετάλλευσης που χρησιμοποιείται για να παρακάμψει μέτρα ασφαλείας όπως το No-Execute (NX) ή το Data Execution Prevention (DEP). Αντί να εισάγει και να εκτελεί κώδικα κέλυφους, ένας επιτιθέμενος εκμεταλλεύεται κομμάτια κώδικα που υπάρχουν ήδη στο δυαδικό αρχείο ή σε φορτωμένες βιβλιοθήκες, γνωστά ως "gadgets". Κάθε gadget τελειώνει συνήθως με μια εντολή ret
και εκτελεί μια μικρή λειτουργία, όπως μεταφορά δεδομένων μεταξύ καταχωρητών ή εκτέλεση αριθμητικών πράξεων. Συνδέοντας αυτά τα gadgets μαζί, ένας επιτιθέμενος μπορεί να κατασκευάσει ένα φορτίο για να εκτελέσει αυθαίρετες λειτουργίες, παρακάμπτοντας αποτελεσματικά τις προστασίες NX/DEP.
Πώς Λειτουργεί το ROP
Απάτηση Ροής Ελέγχου: Αρχικά, ένας επιτιθέμενος πρέπει να απατήσει τη ροή ελέγχου ενός προγράμματος, συνήθως εκμεταλλευόμενος ένα υπερχείλισμα buffer για να αντικαταστήσει μια αποθηκευμένη διεύθυνση επιστροφής στη στοίβα.
Αλυσίδωση Gadgets: Έπειτα, ο επιτιθέμενος επιλέγει προσεκτικά και αλυσίδωνει gadgets για να εκτελέσει τις επιθυμητές ενέργειες. Αυτό θα μπορούσε να περιλαμβάνει την ρύθμιση ορισμάτων για μια κλήση συνάρτησης, την κλήση της συνάρτησης (π.χ.,
system("/bin/sh")
), και τη χειρισμό οποιασδήποτε απαραίτητης καθαριότητας ή επιπλέον λειτουργιών.Εκτέλεση Φορτίου: Όταν η ευάλωτη συνάρτηση επιστρέφει, αντί να επιστρέψει σε μια νόμιμη τοποθεσία, αρχίζει να εκτελεί την αλυσίδα των gadgets.
Εργαλεία
Συνήθως, τα gadgets μπορούν να βρεθούν χρησιμοποιώντας το ROPgadget, το ropper ή απευθείας από τα pwntools (ROP).
ROP Chain σε Παράδειγμα x86
Σύμβαση Κλήσης x86 (32-bit)
cdecl: Ο καλούντας καθαρίζει τη στοίβα. Τα ορίσματα συνάρτησης προστίθενται στη στοίβα με αντίστροφη σειρά (δεξιά προς αριστερά). Τα ορίσματα προστίθενται στη στοίβα από δεξιά προς αριστερά.
stdcall: Παρόμοιο με το cdecl, αλλά ο καλούμενος είναι υπεύθυνος για τον καθαρισμό της στοίβας.
Εύρεση Gadgets
Αρχικά, ας υποθέσουμε ότι έχουμε εντοπίσει τα απαραίτητα gadgets μέσα στο δυαδικό αρχείο ή στις φορτωμένες βιβλιοθήκες. Τα gadgets που μας ενδιαφέρουν είναι:
pop eax; ret
: Αυτό το gadget αποσπά την κορυφαία τιμή της στοίβας στον καταχωρητήEAX
και στη συνέχεια επιστρέφει, επιτρέποντάς μας να ελέγξουμε τοEAX
.pop ebx; ret
: Παρόμοιο με το παραπάνω, αλλά για τον καταχωρητήEBX
, επιτρέποντας τον έλεγχο τουEBX
.mov [ebx], eax; ret
: Μεταφέρει την τιμή στοEAX
στη θέση μνήμης που δείχνει οEBX
και στη συνέχεια επιστρέφει. Αυτό ονομάζεται συχνά gadget γραφής-τι-πού.Επιπλέον, έχουμε διαθέσιμη τη διεύθυνση της συνάρτησης
system()
.
ROP Chain
Χρησιμοποιώντας τα pwntools, προετοιμάζουμε τη στοίβα για την εκτέλεση της αλυσίδας ROP ως εξής με στόχο την εκτέλεση της system('/bin/sh')
, παρατηρήστε πως η αλυσίδα ξεκινά με:
Μια εντολή
ret
για λόγους ευθυγράμμισης (προαιρετικά)Διεύθυνση της συνάρτησης
system
(υποθέτοντας απενεργοποιημένο το ASLR και γνωστή την libc, περισσότερες πληροφορίες στο Ret2lib)Χώρος για τη διεύθυνση επιστροφής από την
system()
Διεύθυνση της συμβολοσειράς
"/bin/sh"
(παράμετρος για τη συνάρτηση system)
Παράδειγμα ROP Chain σε x64
Σύμβαση κλήσης x64 (64-bit)
Χρησιμοποιεί τη System V AMD64 ABI σύμβαση κλήσης σε συστήματα παρόμοια με Unix, όπου οι πρώτες έξι ακέραιες ή δείκτες παραμέτροι περνιούνται στους registes
RDI
,RSI
,RDX
,RCX
,R8
, καιR9
. Επιπλέον παραμέτροι περνιούνται στη στοίβα. Η τιμή επιστροφής τοποθετείται στοRAX
.Η σύμβαση κλήσης Windows x64 χρησιμοποιεί τους
RCX
,RDX
,R8
, καιR9
για τις πρώτες τέσσερις ακέραιες ή δείκτες παραμέτρους, με επιπλέον παραμέτρους που περνιούνται στη στοίβα. Η τιμή επιστροφής τοποθετείται στοRAX
.Καταχωρητές: Οι 64-bit καταχωρητές περιλαμβάνουν τους
RAX
,RBX
,RCX
,RDX
,RSI
,RDI
,RBP
,RSP
, καιR8
έωςR15
.
Εύρεση Gadgets
Για τον σκοπό μας, ας επικεντρωθούμε σε gadgets που θα μας επιτρέψουν να ορίσουμε τον καταχωρητή RDI (για να περάσουμε το string "/bin/sh" ως παράμετρο στη system()) και στη συνέχεια να καλέσουμε τη συνάρτηση system(). Θα υποθέσουμε ότι έχουμε εντοπίσει τα ακόλουθα gadgets:
pop rdi; ret: Αποσυσκευάζει την κορυφαία τιμή της στοίβας στο RDI και στη συνέχεια επιστρέφει. Απαραίτητο για την ορισμό της παραμέτρου μας για την system().
ret: Μια απλή επιστροφή, χρήσιμη για την ευθυγράμμιση της στοίβας σε ορισμένα σενάρια.
Και γνωρίζουμε τη διεύθυνση της συνάρτησης system().
ROP Chain
Παρακάτω υπάρχει ένα παράδειγμα χρησιμοποιώντας το pwntools για να δημιουργήσουμε και να εκτελέσουμε μια ROP chain με στόχο την εκτέλεση της system('/bin/sh') σε x64:
Ευθυγράμμιση Στοίβας
Η x86-64 ABI εξασφαλίζει ότι η στοίβα είναι ευθυγραμμισμένη σε 16 bytes όταν εκτελείται μια εντολή κλήσης. Το LIBC, για βελτιστοποίηση της απόδοσης, χρησιμοποιεί εντολές SSE (όπως movaps) που απαιτούν αυτό το ευθυγράμμισμα. Αν η στοίβα δεν είναι ευθυγραμμισμένη σωστά (δηλαδή το RSP δεν είναι πολλαπλάσιο του 16), κλήσεις σε συναρτήσεις όπως το system θα αποτύχουν σε μια ROP chain. Για να διορθώσετε αυτό, απλά προσθέστε ένα ret gadget πριν καλέσετε το system στην ROP chain σας.
Κύρια Διαφορά μεταξύ x86 και x64
Καθώς το x64 χρησιμοποιεί καταχωρητές για τα πρώτα λίγα ορίσματα, συχνά απαιτεί λιγότερα gadgets από το x86 για απλές κλήσεις συναρτήσεων, αλλά η εύρεση και σύνδεση των σωστών gadgets μπορεί να είναι πιο περίπλοκη λόγω του αυξημένου αριθμού καταχωρητών και του μεγαλύτερου χώρου διευθύνσεων. Ο αυξημένος αριθμός καταχωρητών και ο μεγαλύτερος χώρος διευθύνσεων στην αρχιτεκτονική x64 παρέχουν τόσο ευκαιρίες όσο και προκλήσεις για την ανάπτυξη εκμετάλλευσης, ειδικά στο πλαίσιο του Return-Oriented Programming (ROP).
Last updated