WWW2Exec - atexit()
Last updated
Last updated
Μάθετε & εξασκηθείτε στο Hacking του AWS:Εκπαίδευση HackTricks AWS Red Team Expert (ARTE) Μάθετε & εξασκηθείτε στο Hacking του GCP: Εκπαίδευση HackTricks GCP Red Team Expert (GRTE)
Σήμερα είναι πολύ παράξενο να εκμεταλλεύεστε αυτό!
Το 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
Όπως εξηγείται σε αυτήν την ανάρτηση, Αν το πρόγραμμα εξέρχεται χρησιμοποιώντας 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)
δομή. Βρείτε περισσότερες πληροφορίες εδώ.
__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
Αυτή η τεχνική εξηγείται εδώ και εξαρτάται ξανά από το πρόγραμμα που τερματίζει καλώντας 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 σχετικά με την τεχνική.