WWW2Exec - atexit()
Δομές __atexit
Σήμερα είναι πολύ παράξενο να εκμεταλλεύεστε αυτό!
Το atexit()
είναι μια συνάρτηση στην οποία άλλες συναρτήσεις περνιούνται ως παράμετροι. Αυτές οι συναρτήσεις θα εκτελεστούν κατά την εκτέλεση μιας exit()
ή την επιστροφή του κύριου προγράμματος.
Αν μπορείτε να τροποποιήσετε τη διεύθυνση οποιασδήποτε από αυτές τις συναρτήσεις ώστε να δείχνει σε ένα shellcode για παράδειγμα, τότε θα κερδίσετε έλεγχο της διεργασίας, αλλά αυτό είναι προς το παρόν πιο περίπλοκο.
Προς το παρόν οι διευθύνσεις των συναρτήσεων που πρόκειται να εκτελεστούν είναι κρυμμένες πίσω από αρκετές δομές και τελικά η διεύθυνση στην οποία δείχνει δεν είναι οι διευθύνσεις των συναρτήσεων, αλλά είναι κρυπτογραφημένες με XOR και μετατοπίσεις με ένα τυχαίο κλειδί. Έτσι αυτός ο διανυσματικός επιθετικός δεν είναι πολύ χρήσιμος τουλάχιστον σε x86 και x64_86.
Η συνάρτηση κρυπτογράφησης είναι PTR_MANGLE
. Άλλες αρχιτεκτονικές όπως m68k, mips32, mips64, aarch64, arm, hppa... δεν υλοποιούν τη συνάρτηση κρυπτογράφησης επειδή επιστρέφουν το ίδιο με αυτό που λαμβάνουν ως είσοδο. Έτσι αυτές οι αρχιτεκτονικές θα μπορούσαν να είναι επιθετικές με αυτό το διάνυσμα.
Μπορείτε να βρείτε μια λεπτομερή εξήγηση για το πώς λειτουργεί αυτό στο https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html
link_map
Όπως εξηγείται σε αυτήν την ανάρτηση, Αν το πρόγραμμα εξέρχεται χρησιμοποιώντας return
ή exit()
θα εκτελέσει το __run_exit_handlers()
το οποίο θα καλέσει τους εγγεγραμμένους καταστροφείς.
Αν το πρόγραμμα εξέρχεται μέσω της συνάρτησης _exit()
, θα καλέσει τη κλήση συστήματος exit
και οι χειριστές εξόδου δεν θα εκτελεστούν. Έτσι, για να επιβεβαιώσετε ότι το __run_exit_handlers()
εκτελείται μπορείτε να ορίσετε ένα σημείο ανακοπής σε αυτό.
Ο σημαντικός κώδικας είναι (πηγή):
Σημειώστε πώς map -> l_addr + fini_array -> d_un.d_ptr
χρησιμοποιείται για να υπολογιστεί η θέση του πίνακα συναρτήσεων προς κλήση.
Υπάρχουν μερικές επιλογές:
Αντικαταστήστε την τιμή του
map->l_addr
ώστε να δείχνει σε ένα ψεύτικοfini_array
με οδηγίες για την εκτέλεση αυθαίρετου κώδικαΑντικαταστήστε τις καταχωρήσεις
l_info[DT_FINI_ARRAY]
καιl_info[DT_FINI_ARRAYSZ]
(που είναι περίπου διαδοχικές στη μνήμη), ώστε να κάνουν δείχνουν σε μια πλαστή δομήElf64_Dyn
που θα κάνει ξανά τοarray
να δείχνει σε μια ζώνη μνήμης που ελέγχεται από τον επιτιθέμενο.Αυτή η ανάλυση αντικαθιστά το
l_info[DT_FINI_ARRAY]
με τη διεύθυνση μιας ελεγχόμενης μνήμης στο.bss
που περιέχει ένα ψεύτικοfini_array
. Αυτός ο ψεύτικος πίνακας περιέχει πρώτα μια διεύθυνση one gadget που θα εκτελεστεί και στη συνέχεια τη διαφορά μεταξύ της διεύθυνσης αυτού του ψεύτικου πίνακα και της τιμής τουmap->l_addr
έτσι ώστε το*array
να δείχνει στο ψεύτικο πίνακα.Σύμφωνα με την κύρια ανάρτηση αυτής της τεχνικής και αυτή την ανάλυση το ld.so αφήνει ένα δείκτη στη στοίβα που δείχνει στο δυαδικό
link_map
στο ld.so. Με ένα αυθαίρετο γράψιμο είναι δυνατό να το αντικαταστήσετε και να το κάνετε να δείχνει σε ένα ψεύτικοfini_array
που ελέγχεται από τον επιτιθέμενο με τη διεύθυνση ενός one gadget για παράδειγμα.
Ακολουθώντας τον προηγούμενο κώδικα μπορείτε να βρείτε μια άλλη ενδιαφέρουσα ενότητα με τον κώδικα:
Σε αυτήν την περίπτωση θα ήταν δυνατό να αντικατασταθεί η τιμή του map->l_info[DT_FINI]
που δείχνει σε ένα πλαστό ElfW(Dyn)
δομή. Βρείτε περισσότερες πληροφορίες εδώ.
Αντικατάσταση TLS-Storage dtor_list στο __run_exit_handlers
__run_exit_handlers
Όπως εξηγείται εδώ, αν ένα πρόγραμμα τερματίσει μέσω return
ή exit()
, θα εκτελέσει το __run_exit_handlers()
το οποίο θα καλέσει οποιαδήποτε συνάρτηση καταστροφέων που έχει καταχωρηθεί.
Κώδικας από το _run_exit_handlers()
:
Κώδικας από το __call_tls_dtors()
:
Για κάθε εγγεγραμμένη λειτουργία στο tls_dtor_list
, θα αποκωδικοποιήσει το δείκτη από το cur->func
και θα το καλέσει με το όρισμα cur->obj
.
Χρησιμοποιώντας τη λειτουργία tls
από αυτό το fork του GEF, είναι δυνατό να δούμε ότι πραγματικά η λίστα dtor_list
είναι πολύ κοντά στο stack canary και το PTR_MANGLE cookie. Έτσι, με ένα υπερχείλιση σε αυτό θα ήταν δυνατό να αντικατασταθεί το cookie και το stack canary.
Αν αντικατασταθεί το PTR_MANGLE cookie, θα ήταν δυνατό να παρακάμψει τη λειτουργία PTR_DEMANLE
με το να το ορίσει σε 0x00, πράγμα που σημαίνει ότι το xor
που χρησιμοποιείται για να πάρει την πραγματική διεύθυνση είναι ακριβώς η διεύθυνση που έχει ρυθμιστεί. Έπειτα, γράφοντας στη dtor_list
είναι δυνατό να αλυσιδωθούν αρκετές λειτουργίες με τη διεύθυνση της λειτουργίας και το όρισμά της.
Τέλος, παρατηρήστε ότι ο αποθηκευμένος δείκτης όχι μόνο θα γίνει xor με το cookie αλλά θα περιστραφεί και κατά 17 bits:
Έτσι πρέπει να λάβετε υπόψη αυτό πριν προσθέσετε μια νέα διεύθυνση.
Βρείτε ένα παράδειγμα στην αρχική δημοσίευση.
Άλλες παραμορφωμένες δείκτες στο __run_exit_handlers
__run_exit_handlers
Αυτή η τεχνική εξηγείται εδώ και εξαρτάται ξανά από το πρόγραμμα που τερματίζει καλώντας return
ή exit()
έτσι ώστε να κληθεί το __run_exit_handlers()
.
Ας ελέγξουμε περισσότερο κώδικα αυτής της συνάρτησης:
Η μεταβλητή f
δείχνει στη δομή initial
και ανάλογα με την τιμή του f->flavor
θα κληθούν διαφορετικές συναρτήσεις.
Ανάλογα με την τιμή, η διεύθυνση της συνάρτησης που θα κληθεί θα βρίσκεται σε διαφορετική θέση, αλλά θα είναι πάντα αποκωδικοποιημένη.
Επιπλέον, στις επιλογές ef_on
και ef_cxa
είναι επίσης δυνατό να ελέγξετε ένα όρισμα.
Είναι δυνατό να ελέγξετε τη δομή initial
σε μια συνεδρία εντοπισμού σφαλμάτων με το GEF τρέχοντας gef> p initial
.
Για να εκμεταλλευτείτε αυτό, πρέπει είτε να διαρρεύσετε ή να διαγράψετε το PTR_MANGLE
cookie και στη συνέχεια να αντικαταστήσετε μια εγγραφή cxa
στο initial με system('/bin/sh')
.
Μπορείτε να βρείτε ένα παράδειγμα αυτού στην αρχική ανάρτηση στο blog σχετικά με την τεχνική.
Last updated