Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
vulnerability-in-Remix-React-Router-CVE-2025-31137- — # تحدي CTF يحاكي CVE-2025-31137 في Remix/React Router Express. تعلّم كيفية استغلال ثغرة من جانب الخادم للعثور على علم المسؤول. | Kitploit
أدوات/GitHubGitHub/pouriam23/vulnerability-in-remix-react-router-cve-2025-31137-
تحليل الثغرات الأمنيةالاستغلالاستغلال تطبيقات الويبأمن الويبCTFالتعلم والتعليم
GitHubpouriam23/vulnerability-in-remix-react-router-cve-2025-31137-

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

# تحدي CTF يحاكي CVE-2025-31137 في Remix/React Router Express. تعلّم كيفية استغلال ثغرة من جانب الخادم للعثور على علم المسؤول.

عرض المستودع
14منذ سنة واحدةلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

نظرة عامة

بعد قراءة مقال @zhero___ في منشوره الشخصي على مدونته، قررت بناء مسابقة CTF هذه لتعلم كيفية عمل الأشياء، وبعد ذلك قررت مشاركتها مع أي شخص يريد تعلم كيفية استغلال هذه الثغرة. حاولت إنشاء المسابقة باستخدام الإصدار [email protected]، لكن عندما فحصت @remix-run/express لاحظت أنهم قاموا بتصحيح الكود، فقمت بنسخ ولصق الكود القابل للاستغلال من مستودعهم على GitHub، لذا يجب عليك تغيير كود حزمة @remix-run/express كما سأوضح أدناه.

الهدف

يجب عليك العثور على العلم في صفحة المشرف؛ وبقية أجزاء التطبيق غير فعالة، لذا ركّز فقط على صفحة المشرف واعثر على العلم. كما أنني أوصيك بقراءة هذا المقال الرائع "https://zhero-web-sec.github.io/research-and-things/react-router-and-the-remixed-path" وتعلم كيف اكتشف الباحث هذه الثغرة، ويمكنك أيضًا قراءة الكود لتفهم كيف تعمل الأمور.

البدء

اتبع هذه الخطوات لإعداد المشروع:

1. استنساخ المستودع

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. تثبيت الاعتماديات

تأكد من تثبيت pnpm لديك، ثم نفّذ:

root@kitploit:~
pnpm install

3. تغيير كود خادم Remix Express إلى النسخة القابلة للاستغلال (عندما وجد zhero الثغرة)

استبدل محتويات الملف التالي:

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

بالكود أدناه وأعد تسمية الملف إلى:

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();
  }
}
تنزيل الأداة