SSTI
Server-side template injection (SSTI) occurs when an attacker exploits native template syntax to inject and execute a malicious payload on the server.
Detect
Plaintext context
Most template languages support a ’text’ context where you can directly input HTML
http://vulnerable-website.com/?username=user
The server:
render('Hello ' + username)
Hello user
You might think to test for XSS, but it can also be vulnerable to template injection. If you find XSS, test also for SSTI. So, you should try:
http://vulnerable-website.com/?username=${7*7}
If the output is 49
, it means the mathematical operation is being processed server-side.
Code context
This context is easily missed during assessment because it doesn’t result in obvious XSS.
- First establish that the parameter doesn’t contain a direct XSS vulnerability by injecting HTML
http://vulnerable-website.com/?greeting=data.username<tag>
Without XSS, this usually results in a blank output, encoded tags, or an error message.
- Next, break out of the statement with common templating syntax and inject arbitrary HTML
http://vulnerable-website.com/?greeting=data.username}}<tag>
If this results in an error or blank output, you may have used the wrong templating syntax, or SSTI isn’t possible. If the output renders correctly with the arbitrary HTML, it indicates a SSTI vulnerability.
Hello user<tag>
- Exploit
http://vulnerable-website.com/?greeting=data.username}}<PAYLOAD>
Identification
- Smarty (PHP)
${7*7}
a{*comment*}b
- Mako (Python)
${7*7}
${"z".join("ab")}
- Jinja2 (Python)
{{7*7}}
returns error{{7*'7'}}
returns7777777
- Twig (PHP)
{{7*7}}
returns49
{{7*'7'}}
returns49
- ERB (Ruby)
<%= 7*7 %>
returns49
- Unknown
${7*7}
{{7*'7'}}
- Check if not vulnerable
${7*7}
->{{7*'7'}}
- In this case these payloads don’t have to work