PHP - Deserialization + Autoload Classes
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)
Πρώτα, θα πρέπει να ελέγξετε τι είναι Autoloading Classes.
Βρισκόμαστε σε μια κατάσταση όπου βρήκαμε μια PHP deserialization σε μια webapp χωρίς καμία βιβλιοθήκη ευάλωτη σε gadgets μέσα σε phpggc
. Ωστόσο, στο ίδιο κοντέινερ υπήρχε μια διαφορετική webapp composer με ευάλωτες βιβλιοθήκες. Επομένως, ο στόχος ήταν να φορτώσουμε τον φορτωτή composer της άλλης webapp και να τον εκμεταλλευτούμε για να φορτώσουμε ένα gadget που θα εκμεταλλευτεί αυτή τη βιβλιοθήκη με ένα gadget από την webapp που είναι ευάλωτη σε deserialization.
Βήματα:
Έχετε βρει μια deserialization και δεν υπάρχει κανένα gadget στον τρέχοντα κώδικα της εφαρμογής
Μπορείτε να εκμεταλλευτείτε μια spl_autoload_register
συνάρτηση όπως η παρακάτω για να φορτώσετε οποιοδήποτε τοπικό αρχείο με κατάληξη .php
Για αυτό χρησιμοποιείτε μια deserialization όπου το όνομα της κλάσης θα είναι μέσα σε $name
. Δεν μπορείτε να χρησιμοποιήσετε "/" ή "." σε ένα όνομα κλάσης σε ένα serialized αντικείμενο, αλλά ο κώδικας αντικαθιστά τους υπογραμμούς ("_") με κάθετους ("/"). Έτσι, ένα όνομα κλάσης όπως tmp_passwd
θα μετατραπεί σε /tmp/passwd.php
και ο κώδικας θα προσπαθήσει να το φορτώσει.
Ένα παράδειγμα gadget θα είναι: O:10:"tmp_passwd":0:{}
Αν έχετε μια ανάρτηση αρχείου και μπορείτε να ανεβάσετε ένα αρχείο με κατάληξη .php
μπορείτε να καταχραστείτε αυτή τη λειτουργία άμεσα και να αποκτήσετε ήδη RCE.
Στην περίπτωσή μου, δεν είχα τίποτα τέτοιο, αλλά υπήρχε μέσα στο ίδιο κοντέινερ μια άλλη ιστοσελίδα composer με μια βιβλιοθήκη ευάλωτη σε ένα phpggc
gadget.
Για να φορτώσετε αυτή τη άλλη βιβλιοθήκη, πρώτα πρέπει να φορτώσετε τον φορτωτή composer της άλλης διαδικτυακής εφαρμογής (γιατί ο φορτωτής της τρέχουσας εφαρμογής δεν θα έχει πρόσβαση στις βιβλιοθήκες της άλλης). Γνωρίζοντας τη διαδρομή της εφαρμογής, μπορείτε να το πετύχετε αυτό πολύ εύκολα με: O:28:"www_frontend_vendor_autoload":0:{}
(Στην περίπτωσή μου, ο φορτωτής composer ήταν στο /www/frontend/vendor/autoload.php
)
Τώρα, μπορείτε να φορτώσετε τον φορτωτή composer της άλλης εφαρμογής, οπότε ήρθε η ώρα να δημιουργήσετε το phpgcc
payload για χρήση. Στην περίπτωσή μου, χρησιμοποίησα Guzzle/FW1
, το οποίο μου επέτρεψε να γράψω οποιοδήποτε αρχείο μέσα στο σύστημα αρχείων.
ΣΗΜΕΙΩΣΗ: Το παραγόμενο gadget δεν λειτουργούσε, για να λειτουργήσει έπρεπε να τροποποιήσω αυτό το payload chain.php
του phpggc και να ορίσω όλα τα χαρακτηριστικά των κλάσεων από ιδιωτικά σε δημόσια. Αν όχι, μετά την αποσειριοποίηση της συμβολοσειράς, τα χαρακτηριστικά των δημιουργημένων αντικειμένων δεν είχαν καμία τιμή.
Τώρα έχουμε τον τρόπο να φορτώσουμε τον φορτωτή composer της άλλης εφαρμογής και να έχουμε ένα phpggc payload που λειτουργεί, αλλά πρέπει να το κάνουμε αυτό στην ΙΔΙΑ ΑΙΤΗΣΗ ώστε ο φορτωτής να φορτωθεί όταν χρησιμοποιηθεί το gadget. Για αυτό, έστειλα έναν σειριοποιημένο πίνακα με και τα δύο αντικείμενα όπως:
Μπορείτε να δείτε πρώτα τον φορτωτή να φορτώνεται και μετά το payload
Τώρα, μπορούμε να δημιουργήσουμε και να γράψουμε ένα αρχείο, ωστόσο, ο χρήστης δεν μπορούσε να γράψει σε κανέναν φάκελο μέσα στον web server. Έτσι, όπως μπορείτε να δείτε στο payload, το PHP καλεί system
με κάποιο base64 που δημιουργείται στο /tmp/a.php
. Στη συνέχεια, μπορούμε να ξαναχρησιμοποιήσουμε τον πρώτο τύπο payload που χρησιμοποιήσαμε ως LFI για να φορτώσουμε τον composer loader της άλλης webapp για να φορτώσουμε το παραγόμενο αρχείο /tmp/a.php
. Απλά προσθέστε το στο gadget αποσυμπίεσης:
Περίληψη του payload
Φόρτωση του composer autoload μιας διαφορετικής webapp στο ίδιο container
Φόρτωση ενός phpggc gadget για να εκμεταλλευτεί μια βιβλιοθήκη από την άλλη webapp (η αρχική webapp που ήταν ευάλωτη σε deserialization δεν είχε κανένα gadget στις βιβλιοθήκες της)
Το gadget θα δημιουργήσει ένα αρχείο με ένα PHP payload σε /tmp/a.php με κακόβουλες εντολές (ο χρήστης της webapp δεν μπορεί να γράψει σε κανένα φάκελο καμίας webapp)
Το τελικό μέρος του payload μας θα χρησιμοποιήσει να φορτώσει το παραγόμενο php αρχείο που θα εκτελέσει εντολές
Χρειαζόμουν να καλέσω αυτή τη deserialization δύο φορές. Στις δοκιμές μου, την πρώτη φορά το αρχείο /tmp/a.php
δημιουργήθηκε αλλά δεν φορτώθηκε, και τη δεύτερη φορά φορτώθηκε σωστά.
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)