PoC — linux-entra-sso में Entra ID PRT SSO कुकी एक्सफ़िल्ट्रेशन को सक्षम करने वाली ओरिजिन वैलिडेशन त्रुटि (GHSA-g9vc-5j77-f2cm, CVE-2026-87005, CVSS 5.3)।
CVE स्थिति: अनुरोध किया गया, असाइनमेंट लंबित। यह निष्कर्ष GHSA-g9vc-5j77-f2cm के रूप में प्रकाशित किया गया है। CVE असाइनमेंट पर इस रिपॉज़िटरी का नाम बदलकर
CVE-YYYY-NNNNN-linux-entra-sso-PoCकर दिया जाएगा और इस बैनर को CVE लिंक से बदल दिया जाएगा।
| शोधकर्ता | Dostxodjayev Abdullox (@squeeze440) |
| सलाहकार | GHSA-g9vc-5j77-f2cm |
| CVSS 3.1 | 5.3 (मध्यम) |
| कमज़ोरी | CWE-346, CWE-20 |
linux-entra-sso में Platform.SSO_URL में ट्रेलिंग पाथ सेपरेटर नहीं है, इसलिए Firefox/Thunderbird onBeforeSendHeaders गार्ड (e.url.startsWith(Platform.SSO_URL)) को login.microsoftonline.com.<attacker-domain> के रूप में हमलावर-पंजीकृत किसी भी डोमेन द्वारा बायपास किया जा सकता है, जिससे एक्सटेंशन हमलावर के अपने होस्ट पर भेजे गए अनुरोधों में एक लाइव Entra ID Primary Refresh Token (PRT) SSO कुकी प्राप्त करके इंजेक्ट कर देता है।
siemens/linux-entra-sso — लोकल Microsoft Identity Broker (Intune) के माध्यम से Microsoft Entra ID पर SSO के लिए Linux ब्राउज़र प्लगइन। Firefox बिल्ड व्यावहारिक रूप से शोषणीय है; Thunderbird समान कमज़ोर कोड पथ साझा करता है लेकिन वर्तमान में इस वेक्टर के माध्यम से पहुँच योग्य नहीं है (विवरण देखें); Chrome/Chromium प्रभावित नहीं है (विवरण देखें)।
v1.10.0 (कमिट 676854c, 2026-08-03 तक वर्तमान main)। वर्तमान रिलीज़ में मौजूद होने की पुष्टि की गई, अर्थात GHSA-52rj-42vh-2rxc / CVE-2026-42177 द्वारा ठीक नहीं किया गया (उस फिक्स ने केवल Chrome declarativeNetRequest एडाप्टर को छुआ था)।
5.3 (मध्यम) — CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N
AC:H — शोषण के लिए आवश्यक है कि एक्सटेंशन के पास एक प्रदत्त होस्ट अनुमति हो जो हमलावर के तैयार किए गए होस्टनाम को कवर करती हो। व्यवहार में हमलावर को पीड़ित को हमलावर के पेज पर रहते हुए एक्सटेंशन के "Background SSO (enable)" लिंक पर क्लिक करने के लिए सोशल-इंजीनियर करना पड़ता है — यह एक ऐसी स्थिति है जो हमलावर के सीधे नियंत्रण से बाहर है, जो सहोदर GHSA-52rj-42vh-2rxc के लिए उपयोग किए गए जटिलता तर्क से मेल खाती है।UI:R — अनुमति अनुदान एक स्पष्ट उपयोगकर्ता क्लिक है।C:H — चुराई गई PRT SSO कुकी सीधे login.microsoftonline.com के विरुद्ध रीप्ले की जा सकती है ताकि पीड़ित द्वारा सहमति दिए गए किसी भी ऐप के लिए एक्सेस/ID टोकन बनाए जा सकें (पूर्ण SSO सत्र हाईजैक)।I:N/A:N — बग एक क्रेडेंशियल का खुलासा करता है लेकिन स्वयं डेटा या उपलब्धता को संशोधित नहीं करता।मूल कारण — src/platform.js:9:
static SSO_URL = "https://login.microsoftonline.com";
कोई ट्रेलिंग / नहीं।
कमज़ोर जाँच — platform/firefox/js/platform-firefox.js:55-59:
async #onBeforeSendHeaders(e) {
// filter out requests that are not part of the OAuth2.0 flow
if (!e.url.startsWith(Platform.SSO_URL)) {
return { requestHeaders: e.requestHeaders };
}
...
String.prototype.startsWith एक कच्ची कैरेक्टर-प्रीफिक्स तुलना करता है, होस्टनाम/ओरिजिन तुलना नहीं। चूँकि Platform.SSO_URL में कोई ट्रेलिंग सेपरेटर नहीं है, कोई भी URL जिसका होस्ट login.microsoftonline.com.<anything> है — एक वाक्यात्मक रूप से वैध DNS नाम जिसे हमलावर पूरी तरह नियंत्रित करता है — भी जाँच को संतुष्ट करता है, उदाहरण के लिए:
"https://login.microsoftonline.com.attacker.example/phish".startsWith("https://login.microsoftonline.com")
=> true
यह वही रक्षात्मक जाँच है जिसे GHSA-52rj-42vh-2rxc के अपने विवरण ने "the canonical defensive check ... absent from the Chrome adapter" कहा था — यह यहाँ मौजूद है, लेकिन स्वयं बायपास करने योग्य है, इसलिए सलाहकार के फिक्स (जिसने केवल Chrome के declarativeNetRequest नियम को मज़बूत किया) ने इस पथ को खुला छोड़ दिया। platform/thunderbird/js/platform-thunderbird.js PlatformFirefox को बिना update_request_handlers() या #onBeforeSendHeaders को ओवरराइड किए एक्सटेंड करता है, इसलिए Thunderbird को वही दोष विरासत में मिलता है।
ट्रिगर पथ (update_request_handlers, platform/firefox/js/platform-firefox.js:36-53): लिसनर urls: this.well_known_app_filters के साथ रजिस्टर किया जाता है, जो chrome.permissions.getAll().origins (src/platform.js:78-79, update_host_permissions()) से पॉप्युलेट होता है। उपयोगकर्ता द्वारा प्रदत्त कोई भी होस्ट अनुमति — जिसमें पॉपअप के "Background SSO (enable)" लिंक के माध्यम से एकल-साइट अनुदान भी शामिल है (popup/menu.js:171-260, सक्रिय टैब से प्राप्त current_filter = "https://" + tab_hostname + "/*" का उपयोग करते हुए) — उस सटीक होस्ट के लिए लिसनर रजिस्टर करने के लिए पर्याप्त है। GHSA-52rj-42vh-2rxc में वर्णित शोषण पूर्वापेक्षा के विपरीत, कैच-ऑल https://*/* अनुमति की आवश्यकता नहीं है; यहाँ हमलावर के अपने लुक-अलाइक डोमेन पर एक एकल लक्षित अनुदान पर्याप्त है, जो पूर्व सलाहकार के PoC की तुलना में एक निचली बाधा है।
सिंक — वही फ़ाइल, पंक्तियाँ 60-70:
let prt = await this.#broker.acquirePrtSsoCookie(this.account, e.url);
ssoLog("inject PRT SSO into request headers");
e.requestHeaders.push({ name: prt.cookieName, value: prt.cookieContent });
e.url (पूरा हमलावर URL) सीधे ssoUrl के रूप में नेटिव ब्रोकर को पास किया जाता है। linux-entra-sso.py:27-30 दस्तावेज़ित करता है कि Microsoft ब्रोकर बैकएंड ssoUrl को सर्वर-साइड पर मान्य नहीं करता ("the correct value is not checked ... by the authorization backend"), इसलिए कुकी बिना शर्त जारी की जाती है, और इसे वास्तव में हमलावर के अपने होस्ट पर जा रहे अनुरोध के हेडर में इंजेक्ट किया जाता है — एक सीधा एक्सफिल्ट्रेशन, न कि केवल Microsoft-बाउंड अनुरोध पर सेट किया गया हेडर।
Chrome प्रभावित नहीं है: platform/chrome/js/platform-chrome.js:96-99 (GHSA-52rj-42vh-2rxc फिक्स के बाद, कमिट 8183759) "|" + Platform.SSO_URL + "/" (स्ट्रिंग-आरंभ एंकर + ट्रेलिंग स्लैश) के साथ एंकर करता है और एक स्पष्ट requestDomains: [URL.parse(Platform.SSO_URL).hostname] अनुमति-सूची जोड़ता है — दोनों login.microsoftonline.com.attacker.example होस्ट को सही ढंग से अस्वीकार करते हैं।
Thunderbird — वही कमज़ोर कोड, वर्तमान में इस वेक्टर के माध्यम से पहुँच योग्य नहीं: platform/thunderbird/js/platform-thunderbird.js PlatformFirefox को अपरिवर्तित एक्सटेंड करता है, इसलिए Thunderbird बिल्ड के बाइनरी में समान startsWith बायपास मौजूद है। हालाँकि platform/thunderbird/manifest.json केवल एक निश्चित "host_permissions": ["https://login.microsoftonline.com/*"] घोषित करता है और उसमें कोई optional_host_permissions कुंजी नहीं है। WebExtensions केवल chrome.permissions.request() को उन ओरिजिन्स को अनुदान देने की अनुमति देता है जो optional_permissions/optional_host_permissions में पूर्व-घोषित हों; चूँकि Thunderbird कोई भी घोषित नहीं करता, पॉपअप का "Background SSO (enable)" फ़्लो (popup/menu.js:259-261) आज Thunderbird पर हमलावर-चयनित डोमेन के लिए अनुमति प्राप्त नहीं कर सकता। बग वहाँ अव्यक्त है, वर्तमान में हमलावर-पहुँच योग्य नहीं, और इसे अभी भी डिफेंस-इन-डेप्थ के लिए / इस स्थिति में कि उस मैनिफ़ेस्ट में कभी optional_host_permissions जोड़ा जाए, ठीक किया जाना चाहिए।
वास्तविक शिप किए गए कॉन्स्टेंट (लक्ष्य के src/platform.js से सीधे आयातित, हाथ से कॉपी किया गया नहीं) के विरुद्ध कमज़ोर प्रेडिकेट की गतिशील रूप से पुष्टि की गई। स्क्रिप्ट ~/engagements/linux-entra-sso/evidence/prt_bypass_poc.mjs पर रखी गई है।
$ node prt_bypass_poc.mjs
Real Platform.SSO_URL from src/platform.js: "https://login.microsoftonline.com"
Legit MS URL passes filter (expected true): true
Attacker domain-suffix URL: https://login.microsoftonline.com.attacker.example/phish
Attacker URL passes filter (SHOULD be false, is): true
[CONFIRMED] Platform.SSO_URL lacks a trailing '/', so startsWith()
treats 'login.microsoftonline.com.attacker.example' as an in-scope
SSO endpoint. onBeforeSendHeaders would call:
broker.acquirePrtSsoCookie(this.account, "https://login.microsoftonline.com.attacker.example/phish")
and inject the returned PRT cookie into the request headers sent to
the attacker-controlled host.
शेष श्रृंखला (ब्रोकर द्वारा एक अमान्य ssoUrl के लिए कुकी जारी करना, और WebExtensions webRequest लिसनर का प्रदत्त एकल-होस्ट अनुमति के लिए फायर होना) स्थिर रूप से ट्रेस किया गया है, गतिशील रूप से पुष्टि नहीं की गई — इसे एंड-टू-एंड पुनरुत्पादित करने के लिए एक वास्तविक Entra टेनेंट के विरुद्ध microsoft-identity-broker चलाने वाला एक लाइव नामांकित Linux होस्ट आवश्यक है, जो इस वातावरण से बाहर है। ट्रेस किए गए चरण:
login.microsoftonline.com.attacker.example रजिस्टर करता है और वहाँ एक पेज सर्व करता है।popup/menu.js:259-261 → request_host_permission(["https://login.microsoftonline.com.attacker.example/*"]))।chrome.permissions.onAdded को फायर करता है → on_permissions_changed() (src/background.js:30-34) → update_host_permissions() well_known_app_filters को रीफ्रेश करता है → update_request_handlers() नए होस्ट पैटर्न सहित Firefox webRequest.onBeforeSendHeaders लिसनर को पुनः रजिस्टर करता है।https://login.microsoftonline.com.attacker.example/... के लिए एक main_frame/sub_frame अनुरोध लिसनर को फायर करता है; startsWith जाँच (ऊपर बायपास दिखाया गया) पास हो जाती है।broker.acquirePrtSsoCookie(account, e.url) एक वास्तविक PRT कुकी लौटाता है (linux-entra-sso.py:27-30 के अनुसार, ssoUrl ब्रोकर बैकएंड द्वारा मान्य नहीं किया जाता)।एक हमलावर जो linux-entra-sso Firefox उपयोगकर्ता से एक हमलावर-नियंत्रित लुक-अलाइक डोमेन के लिए "Background SSO" अनुदान प्राप्त कर लेता है, उसे पीड़ित की Entra ID PRT SSO कुकी सीधे अपने सर्वर पर प्राप्त होती है। वह कुकी पीड़ित द्वारा सहमति दिए गए किसी भी एप्लिकेशन के लिए एक्सेस/ID टोकन प्राप्त करने हेतु login.microsoftonline.com के विरुद्ध रीप्ले की जा सकती है — पूर्ण SSO सत्र हाईजैक। पूर्व सलाहकार के विपरीत, इसके लिए व्यापक https://*/* कैच-ऑल अनुमति की आवश्यकता नहीं है, केवल हमलावर के अपने डोमेन पर एकल-साइट अनुदान। Thunderbird वही त्रुटिपूर्ण जाँच शिप करता है लेकिन उसके मैनिफ़ेस्ट में वर्तमान में मनमाने-डोमेन अनुमति को रनटाइम-अनुदान देने का कोई तरीका नहीं है, इसलिए यह आज इस वेक्टर के माध्यम से शोषणीय नहीं है (विवरण देखें)।
कच्चे स्ट्रिंग प्रीफिक्स के बजाय तुलना को उचित ओरिजिन/होस्टनाम जाँच पर एंकर करें, जो Chrome एडाप्टर पर पहले से लागू किए गए फिक्स को प्रतिबिंबित करता है:
if (!e.url.startsWith(Platform.SSO_URL + "/")) {
return { requestHeaders: e.requestHeaders };
}
या, अधिक मज़बूती से, new URL(e.url).origin की तुलना new URL(Platform.SSO_URL).origin से करें (userinfo/port ट्रिक्स को भी अस्वीकार करता है)। फिक्स को Platform.SSO_URL कॉन्स्टेंट स्तर पर लागू करना (src/platform.js में एक बार ट्रेलिंग / जोड़ना) इसे Firefox जाँच और कॉन्स्टेंट के किसी भी अन्य उपभोक्ता दोनों के लिए बंद कर देगा, और एक रिग्रेशन टेस्ट जो दावा करता है कि startsWith https://login.microsoftonline.com.attacker.example/... को अस्वीकार करता है, उसी तरह कवरेज गैप को बंद करेगा जैसे Chrome फिक्स के सुझाए गए testMatchOutcome रिग्रेशन टेस्ट ने GHSA-52rj-42vh-2rxc के लिए किया था।
Dostxodjayev Abdullox (GitHub: squeeze440)
रिपॉज़िटरी में कोई SECURITY.md मौजूद नहीं है और GitHub API किसी रिपॉज़िटरी-स्तरीय सुरक्षा नीति की रिपोर्ट नहीं करता, लेकिन siemens/linux-entra-sso पर GitHub Private Vulnerability Reporting सक्षम है (रिपो की Security टैब "Report a vulnerability" बटन के माध्यम से सत्यापित)। उस चैनल के माध्यम से रिपोर्ट करें: https://github.com/siemens/linux-entra-sso/security/advisories/new।