Server-Side Template Injection in Python
Vulnerable example
The following snippet contains a Flask web application written in Python using Jinja2 templates in an unsafe way, concatenating user-supplied data with a template string.
@app.route("/page")
def page():
name = request.values.get('name')
output = Jinja2.from_string('Hello ' + name + '!').render()
return output
The user-supplied name
variable is concatenated to the template text, allowing an attacker to inject template code. The screenshot shows the attacker injecting 7*7
to demonstrate the result 49
is actually computed.
$ curl -g 'http://localhost:5000/page?name={{7*7}}'
Hello 49!
Depending on which template engine has been used, advanced payloads can be crafted to escape the template sandbox and execute code on the system. The following snippet runs a system command that adds malicious.sh
in the temporary folder. The payload may vary depending on the installation.
$ curl -g 'http://localhost:5000/page?name={{''.__class__.mro()[1].__subclasses__()[46]("touch /tmp/malicious.sh",shell=True)}}'
Prevention
Python template engine API mechanisms automatically enforce the separation between code and data, providing the API are called correctly as shown in the following snippets.
Jinja2
import Jinja2
Jinja2.from_string("Hello {{name}}!").render(name=name)
Mako
from mako.template import Template
Template("Hello ${name}!").render(name=name)
Tornado
template.Template("Hello {{ name }}!").generate(name=name)
References
CWE - CWE-94: Improper Control of Generation of Code (‘Code Injection’) CWE - CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code (‘Eval Injection’) PortSwigger - Server Side Template Injection