visit
Server Side Template Injection (SSTI) bugs are a less commonly known type of vulnerability in web application security. Although these bugs are rare, they can have a significant impact when discovered, often resulting in Remote Code Execution (RCE).
Admin Functionality - Features that allow an admin to customize pages, banners, or other visuals in an application can sometimes offer templating as a feature. Some developers may choose to even allow access to template languages which opens up this vulnerability.
Un-Sanitized Input - Potentially any input that’s returned back to the user, or on another page could lead to SSTI depending on the website’s functionality. Now understanding the use cases for template languages, put on your developer hat and try to think where you would leverage templating
The SSTI Polyglot payload is designed to test for this vulnerability across several frameworks and languages. It can assist in testing when the source is not known, however, it’s more likely to be stopped by input sanitization or WAFs because of the prevalence of this specific payload and the variety in special characters. ${{<%[%'"}}%\.
GET /search?query=${{<%[%'"}}%\.
A simple payload to test if an app is processing Jinja templates is {{7*7}}
, you will see 49 on the page if it’s processing the template.
Advancing the payload, you can attempt to get execution with the below example executing the date
command using Python’s OS package.
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('date').read() }}
Jinja Filter Bypasses
You should also be aware that there are bypasses for Jinja2 WAF and application filters. Filters and associated bypasses are always evolving, however below are common filters you may see.
WAFs may be picking up some part of self.__init__.__globals__.__builtins__
. If this is the case, using attr()
may help as it can access the builtins object directly.
{{ request|attr('builtins')|import('os')|popen('date')|read }}
Digging deeper into filter bypasses, you can have Python help transform your payload! For example, using format()
can transform the payload as it’s being processed the template engine. This helps when some combination of .
or _
are blocked.
{{ request|format('%s%sbuiltins%s%s')|import('os')|popen('date')|read }}
ThymeLeaf Injection
This is one of the most common ones you’ll see in Java, and it has well known exploits for SSTI bugs. To exec a simple test to confirm we have a working template injection bug, you can use this trick again ${7*7}
and if you see 49
in the response and not the template, that’s a sign of an issue.
${T(java.lang.Runtime).getRuntime().exec(‘date’)}
${#rt = @java.lang.Runtime@getRuntime(),#rt.exec(‘date’)}