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
Tools/GitHubGitHub/pouriam23/vulnerability-in-remix-react-router-cve-2025-31137-
SchwachstellenanalyseExploitationWebanwendungs-ExploitationWebsicherheitCTFLernen & Bildung
GitHubpouriam23/vulnerability-in-remix-react-router-cve-2025-31137-

vulnerability-in-Remix-React-Router-CVE-2025-31137-

CTF-Herausforderung, die CVE-2025-31137 in Remix/React Router Express nachbildet. Lerne, eine serverseitige Sicherheitslücke auszunutzen, um die Admin-Flagge zu finden.

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen
Repository anzeigen
1vor 1 JahrNoch nicht geprüft

Übersicht

Nachdem ich den Write-up von @zhero___ in seinem persönlichen Blogbeitrag gelesen hatte, entschied ich mich, diesen CTF zu bauen, um zu verstehen, wie die Dinge funktionieren. Danach beschloss ich, ihn mit allen zu teilen, die lernen möchten, wie man diese Schwachstelle ausnutzt. Ich habe versucht, den CTF mit der Remix-Version 2.16.0 zu erstellen, aber als ich @remix-run/express überprüfte, stellte ich fest, dass sie den Code gepatcht hatten. Also habe ich den anfälligen Code von ihrem GitHub kopiert und eingefügt. Du musst den Code des @remix-run/express-Pakets wie unten beschrieben ändern.

Ziel

Du musst die Flagge auf der Admin-Seite finden. Andere Teile der Anwendung funktionieren nicht, also konzentriere dich nur auf die Admin-Seite und finde die Flagge. Ich empfehle dir außerdem, diesen großartigen Write-up zu lesen: "https://zhero-web-sec.github.io/research-and-things/react-router-and-the-remixed-path" und zu lernen, wie der Forscher diesen Fehler gefunden hat. Du kannst auch den Code lesen und herausfinden, wie alles funktioniert.

Erste Schritte

Befolge diese Schritte, um das Projekt einzurichten:

1. Repository klonen

root@kitploit:~
git clone https://github.com/pouriam23/vulnerability-in-Remix-React-Router-CVE-2025-31137-.git
cd vulnerability-in-Remix-React-Router-CVE-2025-31137-

2. Abhängigkeiten installieren

Stelle sicher, dass pnpm installiert ist, und führe dann aus:

root@kitploit:~
pnpm install

3. Ändere den Remix Express Server-Code zur anfälligen Version (als zhero den Fehler fand)

Ersetze den Inhalt der folgenden Datei:

root@kitploit:~
/my-remix-app/node_modules/@remix-run/express/dist/server.js

mit dem untenstehenden Code und benenne die Datei um in:

root@kitploit:~
server.ts

📄 server.ts

root@kitploit:~
// IDK why this is needed when it's in the tsconfig..........
// YAY PROJECT REFERENCES!
/// <reference lib="DOM.Iterable" />

import type * as express from "express";
import type { AppLoadContext, ServerBuild } from "@remix-run/node";
import {
  createRequestHandler as createRemixRequestHandler,
  createReadableStreamFromReadable,
  writeReadableStreamToWritable,
} from "@remix-run/node";

/**
 * A function that returns the value to use as `context` in route `loader` and
 * `action` functions.
 *
 * You can think of this as an escape hatch that allows you to pass
 * environment/platform-specific values through to your loader/action, such as
 * values that are generated by Express middleware like `req.session`.
 */
export type GetLoadContextFunction = (
  req: express.Request,
  res: express.Response
) => Promise<AppLoadContext> | AppLoadContext;

export type RequestHandler = (
  req: express.Request,
  res: express.Response,
  next: express.NextFunction
) => Promise<void>;

/**
 * Returns a request handler for Express that serves the response using Remix.
 */
export function createRequestHandler({
  build,
  getLoadContext,
  mode = process.env.NODE_ENV,
}: {
  build: ServerBuild | (() => Promise<ServerBuild>);
  getLoadContext?: GetLoadContextFunction;
  mode?: string;
}): RequestHandler {
  let handleRequest = createRemixRequestHandler(build, mode);

  return async (
    req: express.Request,
    res: express.Response,
    next: express.NextFunction
  ) => {
    try {
      let request = createRemixRequest(req, res);
      let loadContext = await getLoadContext?.(req, res);

      let response = await handleRequest(request, loadContext);

      await sendRemixResponse(res, response);
    } catch (error: unknown) {
      next(error);
    }
  };
}

export function createRemixHeaders(
  requestHeaders: express.Request["headers"]
): Headers {
  let headers = new Headers();

  for (let [key, values] of Object.entries(requestHeaders)) {
    if (values) {
      if (Array.isArray(values)) {
        for (let value of values) {
          headers.append(key, value);
        }
      } else {
        headers.set(key, values);
      }
    }
  }

  return headers;
}

export function createRemixRequest(
  req: express.Request,
  res: express.Response
): Request {
  let [, hostnamePort] = req.get("X-Forwarded-Host")?.split(":") ?? [];
  let [, hostPort] = req.get("host")?.split(":") ?? [];
  let port = hostnamePort || hostPort;
  let resolvedHost = `${req.hostname}${port ? `:${port}` : ""}`;
  let url = new URL(`${req.protocol}://${resolvedHost}${req.originalUrl}`);

  let controller: AbortController | null = new AbortController();
  let init: RequestInit = {
    method: req.method,
    headers: createRemixHeaders(req.headers),
    signal: controller.signal,
  };

  if (req.method !== "GET" && req.method !== "HEAD") {
    init.body = createReadableStreamFromReadable(req);
    (init as { duplex: "half" }).duplex = "half";
  }

  res.on("finish", () => (controller = null));
  res.on("close", () => controller?.abort());

  return new Request(url.href, init);
}

export async function sendRemixResponse(
  res: express.Response,
  nodeResponse: Response
): Promise<void> {
  res.statusMessage = nodeResponse.statusText;
  res.status(nodeResponse.status);

  for (let [key, value] of nodeResponse.headers.entries()) {
    res.append(key, value);
  }

  if (nodeResponse.headers.get("Content-Type")?.match(/text\/event-stream/i)) {
    res.flushHeaders();
  }

  if (nodeResponse.body) {
    await writeReadableStreamToWritable(nodeResponse.body, res);
  } else {
    res.end();
  }
}
Tool herunterladen