Saltar a contenido

Server-side template injection (SSTI)

Inyección de plantillas del lado del servidor (SSTI)

Descripción

SSTI, o Server-Side Template Injection, es una vulnerabilidad de seguridad que se produce cuando un atacante puede inyectar código malicioso en un motor de plantillas. Los motores de plantillas se utilizan comúnmente en aplicaciones web para generar contenido dinámico, y SSTI ocurre cuando la entrada del usuario no se valida o sanea adecuadamente antes de incluirse en una plantilla.

# Asumir que user_input contiene datos controlados por el usuario
user_input = params[:input]

# Uso inseguro de ERB
template = ERB.new("<%= #{user_input} %>")
result = template.result(binding)

# Imprimir el resultado
puts result
// Vulnerable PHP code using Twig
$name = $_GET['name'];
echo $twig->render('greet.twig', ['name' => $name]);
# Código de Python vulnerable usando Jinja2
from flask import Flask, render_template, request

app = Flask(__name__)

@app.route('/greet')
def greet():
    # Inyección de entrada de usuario directamente en la plantilla
    username = request.args.get('username')
    return render_template('greet.html', username=username)

Recomendación

  • Evite crear plantillas a partir de la entrada del usuario siempre que sea posible.
  • Considere usar un motor de plantillas simple y sin lógica, como Mustache.
  • Renderice las plantillas en un entorno de pruebas (sandbox) donde los módulos y funciones de riesgo estén deshabilitados.
  • Sanee la entrada del usuario antes de pasarla a la plantilla.

Ejemplos

# app.rb
require 'sinatra'
require 'mustache'

class ExampleTemplate < Mustache
  def initialize(name)
    @name = name
  end

  def greeting
    "Hello, #{@name}!"
  end
end

get '/greet/:name' do
  name = params['name']
  template = ExampleTemplate.new(name)
  erb template.render
end
<!-- index.php -->
<?php
require 'Mustache/Autoloader.php';
Mustache_Autoloader::register();

$template = new Mustache_Engine;

$name = $_GET['name'] ?? 'World';
$data = ['name' => $name];
echo $template->render('Hello, {{name}}!', $data);
?>
from flask import Flask, render_template
from flask import request
import pystache

app = Flask(__name__)

# Definir una plantilla simple de Mustache
template = """
<html>
<head>
    <title>Greeting Page</title>
</head>
<body>
    <h1>Hello, {{name}}!</h1>
</body>
</html>
"""

# Crear un renderizador Mustache
mustache_renderer = pystache.Renderer()

@app.route('/')
def greet_user():
    # Obtener el parámetro de consulta 'name' de la URL
    user_name = request.args.get('name', 'Guest')

    # Renderizar la plantilla con el nombre del usuario
    rendered_template = mustache_renderer.render(template, {'name': user_name})

    # Devolver el HTML renderizado
    return rendered_template

if __name__ == '__main__':
    app.run(debug=True)

Enlaces

Estándares

  • CWE_TOP_25:
    • CWE_94
  • GDPR:
    • ART_5
    • ART_32
  • PCI_STANDARDS:
    • REQ_6_5
    • REQ_11_3
  • SOC2_CONTROLS:
    • CC_2_1
    • CC_3_4
    • CC_4_1
    • CC_7_1
    • CC_7_2
    • CC_7_4
    • CC_7_5
  • HIPAA_CONTROLS:
    • SECURITY212
    • SECURITY213
    • SECURITY255