ROP - Return Oriented Programing
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Return-Oriented Programming (ROP) είναι μια προηγμένη τεχνική εκμετάλλευσης που χρησιμοποιείται για να παρακάμψει μέτρα ασφαλείας όπως το No-Execute (NX) ή το Data Execution Prevention (DEP). Αντί να εισάγει και να εκτελεί shellcode, ένας επιτιθέμενος εκμεταλλεύεται κομμάτια κώδικα που είναι ήδη παρόντα στο δυαδικό αρχείο ή σε φορτωμένες βιβλιοθήκες, γνωστά ως "gadgets". Κάθε gadget συνήθως τελειώνει με μια εντολή ret
και εκτελεί μια μικρή λειτουργία, όπως η μετακίνηση δεδομένων μεταξύ καταχωρητών ή η εκτέλεση αριθμητικών πράξεων. Συνδέοντας αυτά τα gadgets, ένας επιτιθέμενος μπορεί να κατασκευάσει ένα payload για να εκτελέσει αυθαίρετες λειτουργίες, παρακάμπτοντας αποτελεσματικά τις προστασίες NX/DEP.
Hijacking Ροής Ελέγχου: Πρώτα, ένας επιτιθέμενος πρέπει να hijack τη ροή ελέγχου ενός προγράμματος, συνήθως εκμεταλλευόμενος μια υπερχείλιση buffer για να αντικαταστήσει μια αποθηκευμένη διεύθυνση επιστροφής στο stack.
Αλυσίδωση Gadgets: Ο επιτιθέμενος στη συνέχεια επιλέγει προσεκτικά και αλυσόδεσε gadgets για να εκτελέσει τις επιθυμητές ενέργειες. Αυτό μπορεί να περιλαμβάνει τη ρύθμιση παραμέτρων για μια κλήση συνάρτησης, την κλήση της συνάρτησης (π.χ., system("/bin/sh")
), και την διαχείριση οποιασδήποτε απαραίτητης καθαριότητας ή πρόσθετων λειτουργιών.
Εκτέλεση Payload: Όταν η ευάλωτη συνάρτηση επιστρέφει, αντί να επιστρέψει σε μια νόμιμη τοποθεσία, αρχίζει να εκτελεί την αλυσίδα των gadgets.
Συνήθως, τα gadgets μπορούν να βρεθούν χρησιμοποιώντας ROPgadget, ropper ή απευθείας από pwntools (ROP).
cdecl: Ο καλών καθαρίζει το stack. Οι παράμετροι της συνάρτησης τοποθετούνται στο stack σε αντίστροφη σειρά (δεξιά προς τα αριστερά). Οι παράμετροι τοποθετούνται στο stack από δεξιά προς τα αριστερά.
stdcall: Παρόμοιο με το cdecl, αλλά ο καλούμενος είναι υπεύθυνος για τον καθαρισμό του stack.
Πρώτα, ας υποθέσουμε ότι έχουμε εντοπίσει τα απαραίτητα gadgets μέσα στο δυαδικό αρχείο ή στις φορτωμένες βιβλιοθήκες. Τα gadgets που μας ενδιαφέρουν είναι:
pop eax; ret
: Αυτό το gadget αφαιρεί την κορυφαία τιμή του stack στον καταχωρητή EAX
και στη συνέχεια επιστρέφει, επιτρέποντάς μας να ελέγξουμε το EAX
.
pop ebx; ret
: Παρόμοιο με το παραπάνω, αλλά για τον καταχωρητή EBX
, επιτρέποντας τον έλεγχο του EBX
.
mov [ebx], eax; ret
: Μεταφέρει την τιμή στο EAX
στη διεύθυνση μνήμης που υποδεικνύεται από το EBX
και στη συνέχεια επιστρέφει. Αυτό συχνά ονομάζεται write-what-where gadget.
Επιπλέον, έχουμε τη διεύθυνση της συνάρτησης system()
διαθέσιμη.
Χρησιμοποιώντας pwntools, προετοιμάζουμε το stack για την εκτέλεση της ROP αλυσίδας ως εξής, στοχεύοντας να εκτελέσουμε system('/bin/sh')
, σημειώστε πώς η αλυσίδα ξεκινά με:
Μια εντολή ret
για σκοπούς ευθυγράμμισης (προαιρετική)
Διεύθυνση της συνάρτησης system
(υποθέτοντας ότι το ASLR είναι απενεργοποιημένο και γνωστή η libc, περισσότερες πληροφορίες στο Ret2lib)
Θέση για τη διεύθυνση επιστροφής από το system()
Διεύθυνση της συμβολοσειράς "/bin/sh"
(παράμετρος για τη συνάρτηση system)
Χρησιμοποιεί τη System V AMD64 ABI κλήση σε Unix-like συστήματα, όπου τα πρώτα έξι ακέραια ή δείκτες επιχειρήματα περνιούνται στους καταχωρητές 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 που θα μας επιτρέψουν να ρυθμίσουμε τον RDI καταχωρητή (για να περάσουμε τη "/bin/sh" συμβολοσειρά ως επιχείρημα στη system()) και στη συνέχεια να καλέσουμε τη system() συνάρτηση. Θα υποθέσουμε ότι έχουμε εντοπίσει τα εξής gadgets:
pop rdi; ret: Αφαιρεί την κορυφαία τιμή της στοίβας στον RDI και στη συνέχεια επιστρέφει. Απαραίτητο για να ρυθμίσουμε το επιχείρημά μας για τη system().
ret: Μια απλή επιστροφή, χρήσιμη για την ευθυγράμμιση της στοίβας σε ορισμένα σενάρια.
Και γνωρίζουμε τη διεύθυνση της system() συνάρτησης.
Παρακάτω είναι ένα παράδειγμα που χρησιμοποιεί pwntools για να ρυθμίσει και να εκτελέσει μια ROP αλυσίδα με στόχο την εκτέλεση system('/bin/sh') σε x64:
In this example:
Χρησιμοποιούμε το pop rdi; ret
gadget για να ορίσουμε το RDI
στη διεύθυνση του "/bin/sh"
.
Κάνουμε άμεση μετάβαση στη system()
μετά την ρύθμιση του RDI
, με τη διεύθυνση της system() στην αλυσίδα.
Το ret_gadget
χρησιμοποιείται για ευθυγράμμιση αν το περιβάλλον στόχος το απαιτεί, το οποίο είναι πιο συνηθισμένο σε x64 για να διασφαλιστεί η σωστή ευθυγράμμιση της στοίβας πριν από την κλήση συναρτήσεων.
Η x86-64 ABI διασφαλίζει ότι η στοίβα είναι ευθυγραμμισμένη στα 16 byte όταν εκτελείται μια εντολή κλήσης. LIBC, για να βελτιστοποιήσει την απόδοση, χρησιμοποιεί εντολές SSE (όπως movaps) που απαιτούν αυτή την ευθυγράμμιση. Αν η στοίβα δεν είναι σωστά ευθυγραμμισμένη (σημαίνει ότι το RSP δεν είναι πολλαπλάσιο του 16), οι κλήσεις σε συναρτήσεις όπως η system θα αποτύχουν σε μια ROP αλυσίδα. Για να το διορθώσετε, απλά προσθέστε ένα ret gadget πριν από την κλήση της system στην ROP αλυσίδα σας.
Δεδομένου ότι x64 χρησιμοποιεί καταχωρητές για τα πρώτα λίγα επιχειρήματα, συχνά απαιτεί λιγότερα gadgets από το x86 για απλές κλήσεις συναρτήσεων, αλλά η εύρεση και η αλυσίδωση των σωστών gadgets μπορεί να είναι πιο περίπλοκη λόγω του αυξημένου αριθμού καταχωρητών και του μεγαλύτερου χώρου διευθύνσεων. Ο αυξημένος αριθμός καταχωρητών και ο μεγαλύτερος χώρος διευθύνσεων στην αρχιτεκτονική x64 παρέχουν τόσο ευκαιρίες όσο και προκλήσεις για την ανάπτυξη εκμεταλλεύσεων, ειδικά στο πλαίσιο του Return-Oriented Programming (ROP).
Δείτε την παρακάτω σελίδα για αυτές τις πληροφορίες:
Introduction to ARM64v8Stack Canaries: Σε περίπτωση BOF, είναι απαραίτητο να παρακαμφθούν οι αποθηκευμένοι canary της στοίβας για να επαναγραφούν οι δείκτες επιστροφής για να εκμεταλλευτούν μια ROP αλυσίδα.
Έλλειψη Gadgets: Αν δεν υπάρχουν αρκετά gadgets, δεν θα είναι δυνατή η δημιουργία μιας ROP αλυσίδας.
Σημειώστε ότι το ROP είναι απλώς μια τεχνική για την εκτέλεση αυθαίρετου κώδικα. Βασισμένο στο ROP, αναπτύχθηκαν πολλές τεχνικές Ret2XXX:
Ret2lib: Χρησιμοποιεί ROP για να καλέσει αυθαίρετες συναρτήσεις από μια φορτωμένη βιβλιοθήκη με αυθαίρετες παραμέτρους (συνήθως κάτι σαν system('/bin/sh')
.
Ret2Syscall: Χρησιμοποιεί ROP για να προετοιμάσει μια κλήση σε μια syscall, π.χ. execve
, και να εκτελέσει αυθαίρετες εντολές.
EBP2Ret & EBP Chaining: Το πρώτο θα εκμεταλλευτεί το EBP αντί του EIP για να ελέγξει τη ροή και το δεύτερο είναι παρόμοιο με το Ret2lib αλλά σε αυτή την περίπτωση η ροή ελέγχεται κυρίως με διευθύνσεις EBP (αν και είναι επίσης απαραίτητο να ελέγχεται το EIP).
64 bit, Pie και nx ενεργοποιημένα, χωρίς canary, επαναγραφή του RIP με μια διεύθυνση vsyscall
με τον μοναδικό σκοπό να επιστρέψει στην επόμενη διεύθυνση στη στοίβα που θα είναι μια μερική επαναγραφή της διεύθυνσης για να αποκτήσει το μέρος της συνάρτησης που διαρρέει τη σημαία.
arm64, χωρίς ASLR, ROP gadget για να κάνει τη στοίβα εκτελέσιμη και να μεταβεί σε shellcode στη στοίβα.
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)