PHP Tricks
Last updated
Last updated
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Αποκτήστε την προοπτική ενός hacker για τις εφαρμογές σας στο διαδίκτυο, το δίκτυο και το cloud
Βρείτε και αναφέρετε κρίσιμες, εκμεταλλεύσιμες ευπάθειες με πραγματικό επιχειρηματικό αντίκτυπο. Χρησιμοποιήστε τα 20+ προσαρμοσμένα εργαλεία μας για να χαρτογραφήσετε την επιφάνεια επίθεσης, να βρείτε ζητήματα ασφάλειας που σας επιτρέπουν να κλιμακώσετε προνόμια και να χρησιμοποιήσετε αυτοματοποιημένα exploits για να συλλέξετε βασικά αποδεικτικά στοιχεία, μετατρέποντας τη σκληρή δουλειά σας σε πειστικές αναφορές.
Αυτό ισχύει επίσης για τα cookies του phpMyAdmin.
Cookies:
Τοποθεσίες:
Αν χρησιμοποιηθεί το ==
στο PHP, τότε υπάρχουν απρόσμενες περιπτώσεις όπου η σύγκριση δεν συμπεριφέρεται όπως αναμένεται. Αυτό συμβαίνει επειδή το "==" συγκρίνει μόνο τιμές που έχουν μετατραπεί στον ίδιο τύπο, αν θέλετε επίσης να συγκρίνετε ότι ο τύπος των συγκρινόμενων δεδομένων είναι ο ίδιος, πρέπει να χρησιμοποιήσετε το ===
.
Πίνακες συγκρίσεων PHP: https://www.php.net/manual/en/types.comparisons.php
"string" == 0 -> True
Μια συμβολοσειρά που δεν ξεκινά με αριθμό είναι ίση με έναν αριθμό
"0xAAAA" == "43690" -> True
Συμβολοσειρές που αποτελούνται από αριθμούς σε δεκαδική ή εξηρημένη μορφή μπορούν να συγκριθούν με άλλους αριθμούς/συμβολοσειρές με αποτέλεσμα True αν οι αριθμοί ήταν οι ίδιοι (οι αριθμοί σε μια συμβολοσειρά ερμηνεύονται ως αριθμοί)
"0e3264578" == 0 --> True
Μια συμβολοσειρά που ξεκινά με "0e" και ακολουθείται από οτιδήποτε θα είναι ίση με 0
"0X3264578" == 0X --> True
Μια συμβολοσειρά που ξεκινά με "0" και ακολουθείται από οποιοδήποτε γράμμα (το X μπορεί να είναι οποιοδήποτε γράμμα) και ακολουθείται από οτιδήποτε θα είναι ίση με 0
"0e12334" == "0" --> True
Αυτό είναι πολύ ενδιαφέρον γιατί σε ορισμένες περιπτώσεις μπορείτε να ελέγξετε την είσοδο της συμβολοσειράς "0" και κάποιο περιεχόμενο που έχει κατακερματιστεί και συγκρίνεται με αυτό. Επομένως, αν μπορείτε να παρέχετε μια τιμή που θα δημιουργήσει έναν κατακερματισμό που ξεκινά με "0e" και χωρίς κανένα γράμμα, θα μπορούσατε να παρακάμψετε τη σύγκριση. Μπορείτε να βρείτε ήδη κατακερματισμένες συμβολοσειρές με αυτό το φορμά εδώ: https://github.com/spaze/hashes
"X" == 0 --> True
Κάθε γράμμα σε μια συμβολοσειρά είναι ίσο με int 0
Περισσότερες πληροφορίες στο https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09
Τύπος Juggling επηρεάζει επίσης τη λειτουργία in_array()
από προεπιλογή (πρέπει να ορίσετε το τρίτο επιχείρημα σε true για να κάνετε αυστηρή σύγκριση):
Αν αυτή η συνάρτηση χρησιμοποιείται για οποιονδήποτε έλεγχο αυθεντικοποίησης (όπως ο έλεγχος του κωδικού πρόσβασης) και ο χρήστης ελέγχει τη μία πλευρά της σύγκρισης, μπορεί να στείλει έναν κενό πίνακα αντί για μια συμβολοσειρά ως την τιμή του κωδικού πρόσβασης (https://example.com/login.php/?username=admin&password[]=
) και να παρακάμψει αυτόν τον έλεγχο:
Το ίδιο σφάλμα συμβαίνει με strcasecmp()
Ακόμα και αν ===
χρησιμοποιείται μπορεί να υπάρχουν σφάλματα που καθιστούν τη σύγκριση ευάλωτη σε χειρισμό τύπων. Για παράδειγμα, αν η σύγκριση μετατρέπει τα δεδομένα σε διαφορετικό τύπο αντικειμένου πριν από τη σύγκριση:
preg_match()
θα μπορούσε να χρησιμοποιηθεί για να επικυρώσει την είσοδο του χρήστη (ελέγχει αν οποιαδήποτε λέξη/regex από μια μαύρη λίστα είναι παρούσα στην είσοδο του χρήστη και αν δεν είναι, ο κώδικας μπορεί να συνεχίσει την εκτέλεσή του).
Ωστόσο, όταν καθορίζεται η αρχή της regexp preg_match()
ελέγχει μόνο την πρώτη γραμμή της εισόδου του χρήστη, τότε αν με κάποιο τρόπο μπορείτε να στείλετε την είσοδο σε πολλές γραμμές, θα μπορούσατε να παρακάμψετε αυτόν τον έλεγχο. Παράδειγμα:
Για να παρακάμψετε αυτήν την έλεγχο μπορείτε να στείλετε την τιμή με νέες γραμμές urlencoded (%0A
) ή αν μπορείτε να στείλετε δεδομένα JSON, στείλτε τα σε πολλές γραμμές:
Βρείτε ένα παράδειγμα εδώ: https://ramadistra.dev/fbctf-2019-rceservice
(Αυτή η παράκαμψη δοκιμάστηκε προφανώς σε PHP 5.2.5 και δεν μπόρεσα να την κάνω να λειτουργήσει σε PHP 7.3.15)
Αν μπορείτε να στείλετε στο preg_match()
μια έγκυρη πολύ μεγάλη είσοδο, δεν θα μπορεί να την επεξεργαστεί και θα μπορείτε να παρακάμψετε τον έλεγχο. Για παράδειγμα, αν αποκλείει ένα JSON θα μπορούσατε να στείλετε:
From: https://medium.com/bugbountywriteup/solving-each-and-every-fb-ctf-challenge-part-1-4bce03e2ecb0
Trick from: https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223 and https://mizu.re/post/pong
Συνοπτικά, το πρόβλημα συμβαίνει επειδή οι preg_*
συναρτήσεις στην PHP βασίζονται στη βιβλιοθήκη PCRE. Στην PCRE, ορισμένες κανονικές εκφράσεις ταιριάζουν χρησιμοποιώντας πολλές αναδρομικές κλήσεις, οι οποίες καταναλώνουν πολύ χώρο στο στοίβα. Είναι δυνατόν να οριστεί ένα όριο στον αριθμό των επιτρεπόμενων αναδρομών, αλλά στην PHP αυτό το όριο προεπιλέγεται σε 100.000, το οποίο είναι περισσότερο από ό,τι χωράει στο στοίβα.
Αυτή η συζήτηση στο Stackoverflow συνδέθηκε επίσης στην ανάρτηση όπου συζητείται πιο αναλυτικά αυτό το ζήτημα. Η αποστολή μας ήταν τώρα σαφής:
Στείλτε μια είσοδο που θα κάνει την κανονική έκφραση να εκτελέσει 100_000+ αναδρομές, προκαλώντας SIGSEGV, κάνοντάς την preg_match()
να επιστρέψει false
, κάνοντάς την εφαρμογή να πιστεύει ότι η είσοδός μας δεν είναι κακόβουλη, ρίχνοντας την έκπληξη στο τέλος του payload κάτι σαν {system(<verybadcommand>)}
για να αποκτήσουμε SSTI --> RCE --> flag :).
Λοιπόν, σε όρους regex, στην πραγματικότητα δεν κάνουμε 100k "αναδρομές", αλλά μετράμε "βήματα οπισθοχώρησης", τα οποία όπως δηλώνει η τεκμηρίωση PHP προεπιλέγεται σε 1_000_000 (1M) στη μεταβλητή pcre.backtrack_limit
.\ Για να φτάσουμε σε αυτό, 'X'*500_001
θα έχει ως αποτέλεσμα 1 εκατομμύριο βήματα οπισθοχώρησης (500k προς τα εμπρός και 500k προς τα πίσω):
Αν το PHP ανακατευθύνει σε άλλη σελίδα αλλά καμία die
ή exit
συνάρτηση δεν καλείται μετά την κεφαλίδα Location
, το PHP συνεχίζει να εκτελεί και να προσθέτει τα δεδομένα στο σώμα:
Check:
File Inclusion/Path traversalregister_globals: Στο PHP < 4.1.1.1 ή αν είναι κακορυθμισμένο, register_globals μπορεί να είναι ενεργό (ή η συμπεριφορά του να μιμείται). Αυτό σημαίνει ότι σε παγκόσμιες μεταβλητές όπως $_GET αν έχουν μια τιμή π.χ. $_GET["param"]="1234", μπορείτε να την αποκτήσετε μέσω του $param. Επομένως, στέλνοντας HTTP παραμέτρους μπορείτε να αντικαταστήσετε μεταβλητές που χρησιμοποιούνται μέσα στον κώδικα.
Τα PHPSESSION cookies του ίδιου τομέα αποθηκεύονται στην ίδια θέση, επομένως αν μέσα σε έναν τομέα χρησιμοποιούνται διαφορετικά cookies σε διαφορετικές διαδρομές μπορείτε να κάνετε μια διαδρομή να αποκτά πρόσβαση στο cookie της άλλης διαδρομής ρυθμίζοντας την τιμή του cookie της άλλης διαδρομής. Με αυτόν τον τρόπο αν και οι δύο διαδρομές αποκτούν πρόσβαση σε μια μεταβλητή με το ίδιο όνομα μπορείτε να κάνετε την τιμή αυτής της μεταβλητής στη διαδρομή1 να ισχύει για τη διαδρομή2. Και τότε η διαδρομή2 θα θεωρεί έγκυρες τις μεταβλητές της διαδρομής1 (δίνοντας στο cookie το όνομα που αντιστοιχεί σε αυτό στη διαδρομή2).
Όταν έχετε τα ονόματα χρηστών των χρηστών της μηχανής. Ελέγξτε τη διεύθυνση: /~<USERNAME> για να δείτε αν οι php κατάλογοι είναι ενεργοποιημένοι.
Αυτές οι συναρτήσεις χρησιμοποιούνται συνήθως στο PHP για να δημιουργούν κατακερματισμούς από κωδικούς πρόσβασης και για να ελέγχουν αν ένας κωδικός πρόσβασης είναι σωστός σε σύγκριση με έναν κατακερματισμό.
Οι υποστηριζόμενοι αλγόριθμοι είναι: PASSWORD_DEFAULT
και PASSWORD_BCRYPT
(ξεκινά με $2y$
). Σημειώστε ότι PASSWORD_DEFAULT είναι συχνά το ίδιο με PASSWORD_BCRYPT. Και αυτή τη στιγμή, PASSWORD_BCRYPT έχει περιορισμό μεγέθους στην είσοδο των 72bytes. Επομένως, όταν προσπαθείτε να κατακερματίσετε κάτι μεγαλύτερο από 72bytes με αυτόν τον αλγόριθμο, θα χρησιμοποιηθούν μόνο τα πρώτα 72B:
Από αυτή την ανάρτηση στο Twitter μπορείτε να δείτε ότι στέλνοντας περισσότερες από 1000 παραμέτρους GET ή 1000 παραμέτρους POST ή 20 αρχεία, το PHOP δεν θα ρυθμίσει τις κεφαλίδες στην απόκριση.
Επιτρέποντας να παρακαμφθούν για παράδειγμα οι κεφαλίδες CSP που ρυθμίζονται σε κώδικες όπως:
Αν μια σελίδα PHP εκτυπώνει σφάλματα και επιστρέφει κάποια είσοδο που παρέχεται από τον χρήστη, ο χρήστης μπορεί να κάνει τον PHP server να εκτυπώσει κάποια περιεχόμενα αρκετά μεγάλα ώστε όταν προσπαθήσει να προσθέσει τις κεφαλίδες στην απάντηση, ο server να ρίξει ένα σφάλμα. Στο παρακάτω σενάριο, ο επιτιθέμενος έκανε τον server να ρίξει κάποια μεγάλα σφάλματα, και όπως μπορείτε να δείτε στην οθόνη, όταν η PHP προσπάθησε να τροποποιήσει τις πληροφορίες κεφαλίδας, δεν μπόρεσε (έτσι για παράδειγμα η κεφαλίδα CSP δεν στάλθηκε στον χρήστη):
Ελέγξτε τη σελίδα:
PHP SSRFsystem("ls"); &#xNAN;`ls`; shell_exec("ls");
Ελέγξτε αυτό για περισσότερες χρήσιμες συναρτήσεις PHP
Για να εκτελέσετε τον κώδικα στο επιχείρημα "replace" απαιτείται τουλάχιστον μία αντιστοίχιση. Αυτή η επιλογή του preg_replace έχει καταργηθεί από την PHP 5.5.0.
Αυτή η συνάρτηση μέσα στο php σας επιτρέπει να εκτελείτε κώδικα που είναι γραμμένος σε μια συμβολοσειρά προκειμένου να επιστρέφετε true ή false (και ανάλογα με αυτό να αλλάξετε την εκτέλεση). Συνήθως η μεταβλητή χρήστη θα εισαχθεί στη μέση μιας συμβολοσειράς. Για παράδειγμα:
assert("strpos($_GET['page']),'..') === false")
--> Σε αυτή την περίπτωση για να αποκτήσετε RCE θα μπορούσατε να κάνετε:
Θα χρειαστεί να σπάσετε τη σύνταξη του κώδικα, να προσθέσετε το payload σας και στη συνέχεια να το διορθώσετε ξανά. Μπορείτε να χρησιμοποιήσετε λογικές λειτουργίες όπως "and" ή "%26%26" ή "|". Σημειώστε ότι "or", "||" δεν λειτουργεί γιατί αν η πρώτη συνθήκη είναι αληθής, το payload μας δεν θα εκτελεστεί. Με τον ίδιο τρόπο, το ";" δεν λειτουργεί καθώς το payload μας δεν θα εκτελεστεί.
Άλλη επιλογή είναι να προσθέσετε στη συμβολοσειρά την εκτέλεση της εντολής: '.highlight_file('.passwd').'
Άλλη επιλογή (αν έχετε τον εσωτερικό κώδικα) είναι να τροποποιήσετε κάποια μεταβλητή για να αλλάξετε την εκτέλεση: $file = "hola"
Αυτή η συνάρτηση χρησιμοποιείται για να ταξινομήσει έναν πίνακα στοιχείων χρησιμοποιώντας μια συγκεκριμένη συνάρτηση. Για να εκμεταλλευτείτε αυτή τη συνάρτηση:
Μπορείτε επίσης να χρησιμοποιήσετε // για να σχολιάσετε το υπόλοιπο του κώδικα.
Για να ανακαλύψετε τον αριθμό των παρενθέσεων που πρέπει να κλείσετε:
?order=id;}//
: λαμβάνουμε ένα μήνυμα σφάλματος (Parse error: syntax error, unexpected ';'
). Πιθανώς μας λείπει μία ή περισσότερες αγκύλες.
?order=id);}//
: λαμβάνουμε μια προειδοποίηση. Αυτό φαίνεται σωστό.
?order=id));}//
: λαμβάνουμε ένα μήνυμα σφάλματος (Parse error: syntax error, unexpected ')' i
). Πιθανώς έχουμε πάρα πολλές κλειστές αγκύλες.
Αν μπορείτε να ανεβάσετε ένα .htaccess, τότε μπορείτε να ρυθμίσετε διάφορα πράγματα και ακόμη και να εκτελέσετε κώδικα (ρυθμίζοντας ότι τα αρχεία με επέκταση .htaccess μπορούν να εκτελούνται).
Διαφορετικά .htaccess shells μπορούν να βρεθούν εδώ
Αν βρείτε μια ευπάθεια που σας επιτρέπει να τροποποιήσετε τις env variables στο PHP (και μια άλλη για να ανεβάσετε αρχεία, αν και με περισσότερη έρευνα ίσως αυτό μπορεί να παρακαμφθεί), θα μπορούσατε να εκμεταλλευτείτε αυτή τη συμπεριφορά για να αποκτήσετε RCE.
LD_PRELOAD
: Αυτή η env variable σας επιτρέπει να φορτώνετε αυθαίρετες βιβλιοθήκες κατά την εκτέλεση άλλων δυαδικών αρχείων (αν και σε αυτή την περίπτωση μπορεί να μην λειτουργήσει).
PHPRC
: Δίνει οδηγίες στο PHP για πού να εντοπίσει το αρχείο ρύθμισης, συνήθως ονομάζεται php.ini
. Αν μπορείτε να ανεβάσετε το δικό σας αρχείο ρύθμισης, τότε, χρησιμοποιήστε το PHPRC
για να δείξετε στο PHP σε αυτό. Προσθέστε μια είσοδο auto_prepend_file
που να καθορίζει ένα δεύτερο ανεβασμένο αρχείο. Αυτό το δεύτερο αρχείο περιέχει κανονικό PHP κώδικα, ο οποίος εκτελείται από το PHP runtime πριν από οποιονδήποτε άλλο κώδικα.
Ανεβάστε ένα αρχείο PHP που περιέχει τον κώδικα shell μας
Ανεβάστε ένα δεύτερο αρχείο, που περιέχει μια οδηγία auto_prepend_file
που δίνει εντολή στον προεπεξεργαστή PHP να εκτελέσει το αρχείο που ανεβάσαμε στο βήμα 1
Ρυθμίστε τη μεταβλητή PHPRC
στο αρχείο που ανεβάσαμε στο βήμα 2.
Αποκτήστε περισσότερες πληροφορίες σχετικά με το πώς να εκτελέσετε αυτή την αλυσίδα από την αρχική αναφορά.
PHPRC - άλλη επιλογή
Αν δεν μπορείτε να ανεβάσετε αρχεία, μπορείτε να χρησιμοποιήσετε στο FreeBSD το "αρχείο" /dev/fd/0
που περιέχει το stdin
, που είναι το σώμα του αιτήματος που αποστέλλεται στο stdin
:
curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary 'auto_prepend_file="/etc/passwd"'
Ή για να αποκτήσετε RCE, ενεργοποιήστε το allow_url_include
και προσθέστε ένα αρχείο με base64 PHP κώδικα:
curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary $'allow_url_include=1\nauto_prepend_file="data://text/plain;base64,PD8KICAgcGhwaW5mbygpOwo/Pg=="'
Τεχνική από αυτή την αναφορά.
Ο webserver αναλύει τα HTTP αιτήματα και τα περνά σε ένα PHP script εκτελώντας ένα αίτημα όπως http://host/cgi.php?foo=bar
ως php.exe cgi.php foo=bar
, το οποίο επιτρέπει την έγχυση παραμέτρων. Αυτό θα επέτρεπε την έγχυση των παρακάτω παραμέτρων για να φορτώσει τον PHP κώδικα από το σώμα:
Επιπλέον, είναι δυνατόν να εισαχθεί η παράμετρος "-" χρησιμοποιώντας τον χαρακτήρα 0xAD λόγω της μεταγενέστερης κανονικοποίησης του PHP. Ελέγξτε το παράδειγμα εκμετάλλευσης από αυτή την ανάρτηση:
Σε αυτή την ανάρτηση είναι δυνατόν να βρείτε εξαιρετικές ιδέες για να δημιουργήσετε έναν κώδικα brain fuck PHP με πολύ λίγους επιτρεπόμενους χαρακτήρες. Επιπλέον, προτείνεται επίσης ένας ενδιαφέρον τρόπος για να εκτελούνται συναρτήσεις που τους επέτρεψαν να παρακάμψουν αρκετούς ελέγχους:
Κοίτα αν μπορείς να εισάγεις κώδικα σε κλήσεις αυτών των συναρτήσεων (από εδώ):
Αν κάνετε αποσφαλμάτωση μιας εφαρμογής PHP, μπορείτε να ενεργοποιήσετε παγκοσμίως την εκτύπωση σφαλμάτων στο /etc/php5/apache2/php.ini
προσθέτοντας display_errors = On
και να επανεκκινήσετε τον apache: sudo systemctl restart apache2
Μπορείτε να χρησιμοποιήσετε το web www.unphp.net για να αποσυμπιέσετε κώδικα php.
Οι PHP Wrappers και τα πρωτόκολλα θα μπορούσαν να σας επιτρέψουν να παρακάμψετε τις προστασίες εγγραφής και ανάγνωσης σε ένα σύστημα και να το συμβιβάσετε. Για περισσότερες πληροφορίες ελέγξτε αυτή τη σελίδα.
Αν δείτε ότι το Xdebug είναι ενεργοποιημένο σε μια έξοδο phpconfig()
, θα πρέπει να προσπαθήσετε να αποκτήσετε RCE μέσω https://github.com/nqxcode/xdebug-exploit
Αν σε μια σελίδα μπορείς να δημιουργήσεις ένα νέο αντικείμενο μιας αυθαίρετης κλάσης, μπορεί να μπορέσεις να αποκτήσεις RCE, έλεγξε την παρακάτω σελίδα για να μάθεις πώς:
PHP - RCE abusing object creation: new $_GET["a"]($_GET["b"])https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/
Σύμφωνα με αυτή την αναφορά είναι δυνατόν να παραχθεί ένα εύκολο shellcode με αυτόν τον τρόπο:
Έτσι, αν μπορείτε να εκτελέσετε αυθαίρετο PHP χωρίς αριθμούς και γράμματα μπορείτε να στείλετε ένα αίτημα όπως το παρακάτω εκμεταλλευόμενοι αυτό το payload για να εκτελέσετε αυθαίρετο PHP:
Για μια πιο λεπτομερή εξήγηση, ελέγξτε https://ctf-wiki.org/web/php/php/#preg_match
Αποκτήστε την προοπτική ενός χάκερ για τις διαδικτυακές σας εφαρμογές, το δίκτυο και το cloud
Βρείτε και αναφέρετε κρίσιμες, εκμεταλλεύσιμες ευπάθειες με πραγματικό επιχειρηματικό αντίκτυπο. Χρησιμοποιήστε τα 20+ προσαρμοσμένα εργαλεία μας για να χαρτογραφήσετε την επιφάνεια επίθεσης, να βρείτε ζητήματα ασφαλείας που σας επιτρέπουν να κλιμακώσετε προνόμια και να χρησιμοποιήσετε αυτοματοποιημένες εκμεταλλεύσεις για να συλλέξετε βασικά αποδεικτικά στοιχεία, μετατρέποντας τη σκληρή σας δουλειά σε πειστικές αναφορές.
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)