
Proof-of-concept exploit for CVE-2025-55182, demonstrating unauthenticated RCE in React Server Components via insecure deserialization of Server Actions, with detailed reproduction steps and mitigation guidance.
यह रिपॉजिटरी CVE-2025-55182 का एक PoC पुनरुत्पादन है, जो React सर्वर कंपोनेंट्स (RSC) में एक महत्वपूर्ण सुरक्षा भेद्यता है जो अप्रमाणित मनमाना कोड निष्पादन की अनुमति देती है।
यह भेद्यता React सर्वर कंपोनेंट्स द्वारा क्लाइंट अनुरोधों से 'सर्वर एक्शन' को डीसीरियलाइज़ करने के तरीके में मौजूद है। विशेष रूप से, requireModule फ़ंक्शन यह सत्यापित करने में विफल रहा कि अनुरोधित निर्यात नाम मॉड्यूल का प्रत्यक्ष गुण था। इससे हमलावर निर्यातित फ़ंक्शनों के constructor गुण तक पहुंच प्राप्त कर सकते थे, जिससे वैश्विक Function कंस्ट्रक्टर का संदर्भ प्राप्त होता है, जिसका उपयोग मनमाना कोड निष्पादित करने के लिए किया जा सकता है।
यह PoC react-server-dom-webpack लाइब्रेरी में भेद्यता को अलग करने के लिए न्यूनतम Node.js वातावरण का उपयोग करता है, सिर्फ यह सुनिश्चित करने के लिए कि शोषण लाइब्रेरी में बग को प्रदर्शित करता है, किसी फ्रेमवर्क में गलत कॉन्फ़िगरेशन को नहीं।
npmnpm install
[!NOTE]
package.jsonकमजोर संस्करण19.0.0पर पिन किया गया है।
यह स्क्रिप्ट एक रॉ HTTP सर्वर सेट करता है जो अनुरोधों को डिकोड करने के लिए कमजोर React रनटाइम का उपयोग करता है।
# tty1
node --conditions react-server server.js
एक अलग टर्मिनल में, एक्सप्लॉइट चलाएँ। यह सर्वर को एक दुर्भावनापूर्ण Flight पेलोड भेजता है।
# tty2
node exploit.js id
आपको प्रतिक्रिया में कमांड आउटपुट दिखाई देना चाहिए:
अपेक्षित आउटपुट:
Response: uid=0(root) gid=0(root) groups=0(root)
भेद्यता क्यों हुई?
ReactFlightDOMServerNode.js में requireModule फ़ंक्शन मूल रूप से क्लाइंट द्वारा भेजे गए किसी भी name पर भरोसा करता था। यह बिना जाँचे कि क्या वह गुण वास्तव में उजागर किया जाना था, moduleExports[metadata[NAME]] करता था। इसलिए यदि क्लाइंट कहता 'भाई, मुझे यह गुण चाहिए', तो सर्वर बस कहता 'ज़रूर! लो, ये लो दोस्त'।
लोगों को किसी भी गुण तक पहुंच देना बुरा विचार क्यों है?
क्योंकि यह मूल रूप से किसी को भी प्रोटोटाइप श्रृंखला में पहुंचने देता है, यहां तक कि constructor तक, जो बेहद खतरनाक है। यदि मॉड्यूल एक फ़ंक्शन निर्यात करता है (जैसे module.exports = () => {}), तो इसका constructor वस्तुतः वैश्विक Function कंस्ट्रक्टर होता है।
Function कंस्ट्रक्टर प्राप्त करने का मतलब RCE क्यों है?
एक बार जब हमलावर Function कंस्ट्रक्टर प्राप्त कर लेता है, तो वे 'बाउंड सर्वर एक्शन' सुविधा का दुरुपयोग कर सकते हैं। वे उसमें एक स्ट्रिंग बांधते हैं जिसमें दुर्भावनापूर्ण जावास्क्रिप्ट होता है (मूल रूप से इसे new Function("evil code") में बदल देते हैं)। और एक बार जब वह चलता है, तो सर्वर जो भी कोड उन्होंने डाला है उसे निष्पादित करता है।
React वास्तव में उस दुर्भावनापूर्ण फ़ंक्शन को क्यों चलाएगा?
क्योंकि सर्वर एक्शन को ID द्वारा ट्रिगर किया जा सकता है। यदि हमलावर एक एक्शन ID के साथ पेलोड तैयार करता है जो उनके module#constructor संदर्भ की ओर इशारा करता है, तो React इसे एक सामान्य एक्शन की तरह हल करता है और निष्पादित करता है। वह 'एक्शन' वास्तव में उनका दुर्भावनापूर्ण फ़ंक्शन है।
इनमें से किसी भी चीज़ को मान्य क्यों नहीं किया गया?
सिस्टम ने बस यह मान लिया कि सर्वर संदर्भ मेटाडेटा से id और name हमेशा डेवलपर द्वारा परिभाषित मान्य निर्यातों को संदर्भित करेंगे। यह सुनिश्चित करने के लिए hasOwnProperty जैसी कोई सुरक्षा जांच नहीं थी कि अनुरोधित गुण वास्तव में एक वास्तविक निर्यात है न कि प्रोटोटाइप श्रृंखला से विरासत में मिली कोई चीज़।
server.js के बजाय Next.js क्यों?मैं React सर्वर कंपोनेंट्स रनटाइम को मैन्युअल रूप से कॉन्फ़िगर करने के लिए एक रॉ server.js (और एक सहायक webpack-runtime.js) का उपयोग करता हूं। यह हमें इसकी अनुमति देता है:
module.exports = fn)। एक वास्तविक बंडलर अपने कॉन्फ़िग के आधार पर निर्यात को लपेटने के तरीके को बदल सकता है।react-server-dom-webpack के अंदर है, न कि Next.js में।react-server-dom-webpack मानता है कि यह Webpack बंडल के अंदर चल रहा है। हमारा webpack-runtime.js इसे वे ग्लोबल देता है जिनकी यह अपेक्षा करता है (__webpack_require__, __webpack_chunk_load__)।
यह भेद्यता का मजाक नहीं है, यह केवल लाइब्रेरी को न्यूनतम रनटाइम दे रहा है जिसकी उसे वास्तव में काम करने के लिए आवश्यकता है।ऐसे 'अमान्य PoCs' के बारे में चर्चा हुई है जो केवल तभी काम करते हैं जब डेवलपर जानबूझकर child_process.exec जैसी खतरनाक चीज़ों को उजागर करता है।
यह PoC उनमें से एक नहीं है। यह एक सामान्य, सुरक्षित सेटअप पर काम करता है।
उजागर किया गया फ़ंक्शन हानिरहित है
ऐप एक सरल updateProfile फ़ंक्शन उजागर करता है जो सिर्फ एक स्ट्रिंग लौटाता है और कुछ भी संदिग्ध नहीं, कोई शेल कमांड नहीं।
एक्सप्लॉइट उस फ़ंक्शन से पूरी तरह बच जाता है
भेद्यता हमलावर को सुरक्षित निर्यात को अनदेखा करने और सीधे updateProfile.constructor पर जाने देती है, जो वैश्विक Function कंस्ट्रक्टर है।
मुख्य मुद्दा गुण पहुंच है
React को .constructor तक पहुंच की अनुमति नहीं देनी चाहिए थी। डेवलपर ने Function कंस्ट्रक्टर को उजागर करने का इरादा नहीं किया था, इसके बजाय, असुरक्षित डीसीरियलाइज़ेशन ने उनके लिए ऐसा किया।
एकमात्र वास्तविक आवश्यकता यह है कि मॉड्यूल सीधे एक फ़ंक्शन निर्यात करता है (module.exports = fn), जो CommonJS और कई बंडलर सेटअपों में बहुत सामान्य है।
exploit.js में पेलोड तीन चंक के साथ एक React Flight संदेश तैयार करता है:
id: "user-profile-action#constructor", जिसका अर्थ है "मुझे कंस्ट्रक्टर दो"।bound: चंक 2 की ओर इशारा करता है, जिसमें तर्क होते हैं।["console.log('nice try, diddy!')"]: दुर्भावनापूर्ण कोड स्ट्रिंग।जब React इसे डीसीरियलाइज़ करता है:
user-profile-action को हल करता है।.constructor गुण पढ़ता है => वैश्विक Function प्राप्त करता है।new Function("console.log('nice try, diddy!')")और यही RCE है!
तुरंत पैच किए गए संस्करणों में अपग्रेड करें:
react-server-dom-webpack >= 19.0.1react-server-dom-parcel >= 19.0.1react-server-dom-turbopack >= 19.0.1पैच विरासत में मिली संपत्तियों तक पहुंच को रोकने के लिए hasOwnProperty जांच शुरू करता है और base64 फ़ाइल अपलोड को प्रतिबंधित करता है।
यदि आप इस PoC को पैच किए गए संस्करण के विरुद्ध चलाते हैं, तो सर्वर क्रैश हो जाएगा या त्रुटि देगा:
$ node --conditions react-server server.js
Listening on http://localhost:3000
/path/to/CVE-2025-55182/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js:2726
resolvedValue = resolvedValue.bind.apply(
^
TypeError: Cannot read properties of undefined (reading 'bind')
at /path/to/CVE-2025-55182/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js:2726:43
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Node.js v20.19.3
यह पुष्टि करता है कि एक्सप्लॉइट constructor गुण तक पहुंचने में विफल रहा (इसने Function के बजाय undefined लौटाया), और इस प्रकार बाद का .bind कॉल विफल हो गया।
यह कोड केवल शैक्षिक और परीक्षण उद्देश्यों के लिए है। इस शोषण का उपयोग उन सिस्टमों के विरुद्ध न करें जिनके आप मालिक नहीं हैं या जिनके परीक्षण की आपको स्पष्ट अनुमति नहीं है।
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE के तहत जारी किया गया।