
प्रमाण-अवधारणा (PoC) एक प्रमाणीकरण बायपास भेद्यता के लिए जो pac4j-jwt के साथ JWE (JSON Web Encryption) का उपयोग करने वाले अनुप्रयोगों को प्रभावित करती है।
अस्वीकरण: यह एक्सप्लॉइट केवल सेवानिवृत्त HackTheBox मशीन "Principal" के लिए विकसित किया गया था। केवल शैक्षिक उद्देश्यों के लिए। उन सिस्टमों के विरुद्ध उपयोग न करें जिनके स्वामी आप नहीं हैं या जिनके परीक्षण की स्पष्ट अनुमति आपके पास नहीं है।
| फ़ील्ड | विवरण |
|---|
| नाम | Principal |
| प्लेटफ़ॉर्म | HackTheBox |
| कठिनाई | — |
| स्थिति | सेवानिवृत्त |
प्रभावित लाइब्रेरी: pac4j-jwt < 4.5.9 / 5.7.9 / 6.3.3
गंभीरता: क्रिटिकल
प्रकार: प्रमाणीकरण बायपास
JwtAuthenticator में एक लॉजिक दोष एक हमलावर को एक अहस्ताक्षरित PlainJWT (alg=none) को JWE (एन्क्रिप्टेड JWT) के अंदर लपेटकर प्रमाणीकरण को बायपास करने की अनुमति देता है।
जब सर्वर JWE को डिक्रिप्ट करता है, तो यह आंतरिक टोकन को SignedJWT के रूप में पार्स करने का प्रयास करता है। क्योंकि आंतरिक टोकन एक PlainJWT है, SignedJWT ऑब्जेक्ट null होता है और हस्ताक्षर सत्यापन पूरी तरह से छोड़ दिया जाता है। सर्वर फिर असत्यापित दावों से एक उपयोगकर्ता प्रोफ़ाइल बनाता है — जिससे किसी भी उपयोगकर्ता, जिसमें एडमिन भी शामिल हैं, का पूर्ण प्रतिरूपण संभव हो जाता है।
दुर्भावनापूर्ण दावे बनाएं (sub=admin, role=ROLE_ADMIN)
↓
अहस्ताक्षरित PlainJWT बनाएं (alg=none)
↓
सर्वर की RSA सार्वजनिक कुंजी का उपयोग करके PlainJWT को JWE के अंदर लपेटें
↓
सर्वर को JWE टोकन सबमिट करें
↓
सर्वर JWE डिक्रिप्ट करता है → PlainJWT पाता है → हस्ताक्षर जांच छोड़ता है → पहुंच प्रदान करता है
exploit.py देखें
pac4j-jwt को पैच किए गए संस्करण में अपग्रेड करें:
4.5.9 या बाद का5.7.9 या बाद का6.3.3 या बाद काया JWE डिक्रिप्शन के बाद PlainJWT आंतरिक टोकन को स्पष्ट रूप से अस्वीकार करें:
if (jwt instanceof PlainJWT) {
throw new CredentialsException("PlainJWT not allowed inside JWE");
}
/api/auth/jwks
alg: noneसार्वजनिक कुंजी का उपयोग करके JWE के अंदर लपेटें
इस रूप में भेजें:
Authorization: Bearer <token>
pip install jwcrypto requests
python3 poc.py \
--jwks-url http://target/api/auth/jwks \
--target http://target/api/dashboard
[+] Forged Token:
eyJhbGciOiJSU0EtT0FFUC0yNTYi...
[+] Browser Injection:
sessionStorage.setItem("auth_token", "eyJhbGciOiJSU0EtT0FFUC0yNTYi...")
[+] Status: 200
{"user":{"username":"admin","role":"ROLE_ADMIN"}}
DevTools → Console खोलें:
sessionStorage.setItem("auth_token", "<PASTE_TOKEN_HERE>")
फिर नेविगेट करें:
/dashboard
alg: none वाले टोकन अस्वीकार करें