Leaking libc address with ROP
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)
Βρείτε overflow offset
Βρείτε POP_RDI
gadget, PUTS_PLT
και MAIN
gadgets
Χρησιμοποιήστε τα προηγούμενα gadgets για να διαρρεύσετε τη διεύθυνση μνήμης του puts ή άλλης libc συνάρτησης και βρείτε την έκδοση libc (κατεβάστε το)
Με τη βιβλιοθήκη, υπολογίστε το ROP και εκμεταλλευτείτε το
This tutorial is going to exploit the code/binary proposed in this tutorial: https://tasteofsecurity.com/security/ret2libc-unknown-libc/ Another useful tutorials: https://made0x78.com/bseries-ret2libc/, https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html
Filename: vuln.c
Κατεβάστε το exploit και τοποθετήστε το στον ίδιο φάκελο με το ευάλωτο δυαδικό αρχείο και δώστε τα απαραίτητα δεδομένα στο σενάριο:
Leaking libc - templateΤο πρότυπο χρειάζεται ένα offset πριν συνεχίσει με το exploit. Αν παρέχεται κάποιο, θα εκτελέσει τον απαραίτητο κώδικα για να το βρει (κατά προεπιλογή OFFSET = ""
):
Εκτελέστε python template.py
θα ανοίξει μια κονσόλα GDB με το πρόγραμμα που έχει καταρρεύσει. Μέσα σε αυτήν την κονσόλα GDB εκτελέστε x/wx $rsp
για να αποκτήσετε τα bytes που θα αντικαθιστούσαν το RIP. Τέλος, αποκτήστε την απόσταση χρησιμοποιώντας μια κονσόλα python:
Αφού βρείτε την απόσταση (σε αυτή την περίπτωση 40) αλλάξτε τη μεταβλητή OFFSET μέσα στο πρότυπο χρησιμοποιώντας αυτή την τιμή.
OFFSET = "A" * 40
Ένας άλλος τρόπος θα ήταν να χρησιμοποιήσετε: pattern create 1000
-- εκτελέστε μέχρι το ret -- pattern seach $rsp
από το GEF.
Τώρα πρέπει να βρούμε ROP gadgets μέσα στο δυαδικό αρχείο. Αυτά τα ROP gadgets θα είναι χρήσιμα για να καλέσουμε puts
για να βρούμε τη libc που χρησιμοποιείται, και αργότερα για να εκκινήσουμε την τελική εκμετάλλευση.
Ο PUTS_PLT
είναι απαραίτητος για να καλέσουμε τη συνάρτηση puts.
Ο MAIN_PLT
είναι απαραίτητος για να καλέσουμε ξανά τη κύρια συνάρτηση μετά από μία αλληλεπίδραση για να εκμεταλλευτούμε την υπερχείλιση ξανά (άπειροι γύροι εκμετάλλευσης). Χρησιμοποιείται στο τέλος κάθε ROP για να καλέσει ξανά το πρόγραμμα.
Ο POP_RDI είναι απαραίτητος για να περάσουμε μια παράμετρο στη καλούμενη συνάρτηση.
Σε αυτό το βήμα δεν χρειάζεται να εκτελέσετε τίποτα καθώς όλα θα βρεθούν από το pwntools κατά την εκτέλεση.
Τώρα είναι η ώρα να βρούμε ποια έκδοση της βιβλιοθήκης libc χρησιμοποιείται. Για να το κάνουμε αυτό, θα διαρρεύσουμε τη διεύθυνση στη μνήμη της συνάρτησης puts
και στη συνέχεια θα αναζητήσουμε σε ποια έκδοση βιβλιοθήκης βρίσκεται η έκδοση του puts σε αυτή τη διεύθυνση.
Για να το κάνετε αυτό, η πιο σημαντική γραμμή του εκτελούμενου κώδικα είναι:
Αυτό θα στείλει μερικά bytes μέχρι να είναι δυνατό το overwriting του RIP: OFFSET
.
Στη συνέχεια, θα ρυθμίσει τη διεύθυνση του gadget POP_RDI
έτσι ώστε η επόμενη διεύθυνση (FUNC_GOT
) να αποθηκευτεί στο RDI registry. Αυτό συμβαίνει επειδή θέλουμε να καλέσουμε το puts περνώντας του τη διεύθυνση του PUTS_GOT
καθώς η διεύθυνση στη μνήμη της συνάρτησης puts αποθηκεύεται στη διεύθυνση που δείχνει το PUTS_GOT
.
Μετά από αυτό, θα κληθεί το PUTS_PLT
(με το PUTS_GOT
μέσα στο RDI) έτσι ώστε το puts να διαβάσει το περιεχόμενο μέσα στο PUTS_GOT
(η διεύθυνση της συνάρτησης puts στη μνήμη) και θα το εκτυπώσει.
Τέλος, η κύρια συνάρτηση καλείται ξανά ώστε να μπορέσουμε να εκμεταλλευτούμε την υπερχείλιση ξανά.
Με αυτόν τον τρόπο έχουμε παραπλανήσει τη συνάρτηση puts να εκτυπώσει τη διεύθυνση στη μνήμη της συνάρτησης puts (η οποία είναι μέσα στη βιβλιοθήκη libc). Τώρα που έχουμε αυτή τη διεύθυνση μπορούμε να αναζητήσουμε ποια έκδοση libc χρησιμοποιείται.
Καθώς εκμεταλλευόμαστε κάποια τοπική δυαδική, δεν είναι απαραίτητο να καταλάβουμε ποια έκδοση της libc χρησιμοποιείται (απλά βρείτε τη βιβλιοθήκη στο /lib/x86_64-linux-gnu/libc.so.6
).
Αλλά, σε περίπτωση απομακρυσμένης εκμετάλλευσης, θα εξηγήσω εδώ πώς μπορείτε να το βρείτε:
Μπορείτε να αναζητήσετε ποια βιβλιοθήκη χρησιμοποιείται στη σελίδα: https://libc.blukat.me/ Θα σας επιτρέψει επίσης να κατεβάσετε την ανακαλυφθείσα έκδοση της libc
Μπορείτε επίσης να κάνετε:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
Αυτό θα πάρει λίγο χρόνο, να είστε υπομονετικοί. Για να λειτουργήσει αυτό, χρειαζόμαστε:
Όνομα συμβόλου libc: puts
Διεύθυνση libc που έχει διαρρεύσει: 0x7ff629878690
Μπορούμε να καταλάβουμε ποια libc είναι πιο πιθανό να χρησιμοποιείται.
Παίρνουμε 2 αντιστοιχίες (θα πρέπει να δοκιμάσετε τη δεύτερη αν η πρώτη δεν λειτουργεί). Κατεβάστε την πρώτη:
Αντιγράψτε τη libc από libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
στον κατάλογο εργασίας μας.
Σε αυτό το σημείο θα πρέπει να γνωρίζουμε τη βιβλιοθήκη libc που χρησιμοποιείται. Καθώς εκμεταλλευόμαστε ένα τοπικό δυαδικό αρχείο, θα χρησιμοποιήσω απλώς: /lib/x86_64-linux-gnu/libc.so.6
Έτσι, στην αρχή του template.py
αλλάξτε τη μεταβλητή libc σε: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Ορίστε τη διαδρομή της βιβλιοθήκης όταν την γνωρίζετε
Δίνοντας τη διαδρομή στη βιβλιοθήκη libc, το υπόλοιπο της εκμετάλλευσης θα υπολογιστεί αυτόματα.
Μέσα στη συνάρτηση get_addr
, η βάση διεύθυνση της libc θα υπολογιστεί:
Σημειώστε ότι η τελική διεύθυνση βάσης της libc πρέπει να τελειώνει σε 00. Αν αυτό δεν ισχύει για εσάς, μπορεί να έχετε διαρρεύσει μια λανθασμένη βιβλιοθήκη.
Στη συνέχεια, η διεύθυνση της συνάρτησης system
και η διεύθυνση της συμβολοσειράς "/bin/sh" θα υπολογιστούν από τη βάση της libc και θα δοθούν τη βιβλιοθήκη libc.
Τέλος, η εκμετάλλευση εκτέλεσης /bin/sh θα προετοιμαστεί για αποστολή:
Ας εξηγήσουμε αυτό το τελικό ROP.
Το τελευταίο ROP (rop1
) κατέληξε να καλεί ξανά τη βασική συνάρτηση, οπότε μπορούμε να εκμεταλλευτούμε ξανά την υπερχείλιση (γι' αυτό το OFFSET
είναι εδώ ξανά). Στη συνέχεια, θέλουμε να καλέσουμε το POP_RDI
δείχνοντας στη διεύθυνση του "/bin/sh" (BINSH
) και να καλέσουμε τη συνάρτηση system (SYSTEM
) επειδή η διεύθυνση του "/bin/sh" θα περαστεί ως παράμετρος.
Τέλος, η διεύθυνση της συνάρτησης εξόδου είναι καλούμενη ώστε η διαδικασία να εξέρχεται ωραία και να μην δημιουργείται καμία ειδοποίηση.
Με αυτόν τον τρόπο η εκμετάλλευση θα εκτελέσει ένα _/bin/sh_** shell.**
Μπορείτε επίσης να χρησιμοποιήσετε ONE_GADGET για να αποκτήσετε ένα shell αντί να χρησιμοποιήσετε system και "/bin/sh". ONE_GADGET θα βρει μέσα στη βιβλιοθήκη libc κάποιον τρόπο να αποκτήσει ένα shell χρησιμοποιώντας μόνο μία διεύθυνση ROP.
Ωστόσο, συνήθως υπάρχουν κάποιους περιορισμοί, οι πιο κοινοί και εύκολοι να αποφευχθούν είναι όπως [rsp+0x30] == NULL
Καθώς ελέγχετε τις τιμές μέσα στο RSP απλά πρέπει να στείλετε μερικές περισσότερες NULL τιμές ώστε να αποφευχθεί ο περιορισμός.
Μπορείτε να βρείτε ένα πρότυπο για να εκμεταλλευτείτε αυτήν την ευπάθεια εδώ:
Leaking libc - templateΕάν το σύμβολο "main" δεν υπάρχει. Τότε μπορείτε να βρείτε πού είναι ο κύριος κώδικας:
και ορίστε τη διεύθυνση χειροκίνητα:
Αν το δυαδικό αρχείο δεν χρησιμοποιεί Puts, θα πρέπει να ελέγξετε αν χρησιμοποιεί
sh: 1: %s%s%s%s%s%s%s%s: not found
Αν βρείτε αυτό το σφάλμα μετά τη δημιουργία όλων των εκμεταλλεύσεων: sh: 1: %s%s%s%s%s%s%s%s: not found
Δοκιμάστε να αφαιρέσετε 64 bytes από τη διεύθυνση του "/bin/sh":
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)