
إثبات مفهوم تفاضلي لـ CVE-2026-40176، يوضح حقن أوامر نظام التشغيل في برنامج تشغيل Perforce الخاص بـ Composer عبر عنوان URL ضار لمستودع، مع اختبار A/B آلي ضد الإصدارات المتأثرة والثابتة.
مثال عملي ذاتي الاحتواء وبأسلوب البرمجة الكائنية (OOP) بلغة PHP يوضح ويتحقق تفاضليًا من ثغرة حقن الأوامر في برنامج تشغيل مستودع Perforce الخاص بـ Composer.
يقوم إثبات المفهوم (PoC) بتشغيل نفس composer.json الخبيث ضد إصدارين من Composer — إصدار متأثر (2.9.5) وإصدار مُصحح (2.9.6) — ويثبت وجود الثغرة من خلال ملاحظة أثر جانبي (ملف علامة مكتوب بواسطة أمر شل محقون) يحدث في الإصدار المتأثر ولكن ليس في الإصدار المُصحح.
⚠️ لأغراض البحث الأمني المصرح به والاختبار الدفاعي فقط. راجع الاستخدام المسؤول.
| CVE | CVE-2026-40176 |
| المكون | Composer — برنامج تشغيل مستودع/VCS لـ Perforce (perforce) |
| الفئة | حقن أوامر نظام التشغيل عبر عنوان URL لمستودع يتحكم به المهاجم |
| سطح الهجوم | ملف composer.json يحتوي على إدخال repositories مُعدّل من النوع type: perforce |
| المتأثر | Composer 2.9.5 |
| المُصحح | Composer 2.9.6 |
| التفعيل | حل/تحديث التبعيات (composer update) ضد المانيفست الخبيث |
| التأثير | تنفيذ أوامر عشوائية على الجهاز الذي يعمل عليه Composer |
| لغة إثبات المفهوم | PHP (ملف واحد، بدون تبعيات خارجية) |
يمكن لـ Composer حل الحزم من عدة أنظمة للتحكم في الإصدارات. بالنسبة لـ Perforce، يتم تحديد المستودع بواسطة رابط p4:// يشفر المضيف والمنفذ والمستخدم/التيار. عندما يبني برنامج تشغيل Perforce الخاص بـ Composer سطر أوامر p4 الأساسي، لا يتم تنظيف الحقول المأخوذة من عنوان URL الذي يتحكم به المهاجم بشكل كافٍ قبل تمريرها إلى شل.
نظرًا لأن مؤلف المانيفست يتحكم بشكل كامل في عنوان URL للمستودع، فإن المهاجم الذي يمكنه جعل الضحية تشغيل composer update/composer install ضد ملف composer.json خبيث (على سبيل المثال، تبعية مسمومة، مستودع معادٍ، أو وظيفة CI تعالج ملفات مشروع غير موثوقة) يمكنه الخروج من استدعاء p4 المقصود وتنفيذ أوامر نظام تشغيل عشوائية بصلاحيات عملية Composer.
ينتمي هذا إلى نفس عائلة مشكلات حقن الوسائط في برامج تشغيل VCS التاريخية لـ Composer، حيث تتدفق قيم URL/الفرع/التيار إلى أوامر الشل دون هروب. يعمل Composer 2.9.6 على تقوية برنامج تشغيل Perforce بحيث لا يتم تنفيذ الحمولة المحقونة بعد الآن.
الوصف الموثوق للسلوك الموضح هنا هو مصدر إثبات المفهوم نفسه (
CVE202640176Test.php)؛ راجع الإعلان الرسمي وسجل تغييرات Composer للحصول على تفاصيل الإصلاح من المنبع.
إثبات المفهوم هو فئة واحدة، CVE202640176Test، تقوم بتجربة A/B (تفاضلية) محكومة:
--version على كل من إصداري Composer المتأثر (2.9.5) والمُصحح (2.9.6) ويتوقف مبكرًا إذا تعذر استدعاء أي منهما.composer.json الذي يحتوي قسم repositories على إدخال perforce برابط p4:// خبيث يحمل حمولة شل محقونة.composer update في ذلك الدليل.finally تستعيد دائمًا ملف composer.json الأصلي في دليل المشروع.PASS فقط عندما يُظهر التشغيل المتأثر الأثر الجانبي ولا يظهره التشغيل المُصحح.لكل تشغيل، تتحقق validateRun() من ثلاثة أشياء:
| الفحص | ما يثبته |
|---|---|
| وجود ملف العلامة واحتوائه على معرف التشغيل | أن حمولة touch/echo المحقونة قد نُفذت بالفعل — أي نجاح حقن الأمر. |
ذكر مخرجات Composer لـ p4 | أن مسار كود برنامج تشغيل Perforce قد تم الوصول إليه (تمت معالجة الحمولة بواسطة المكون الصحيح، وليس خطوة غير ذات صلة). |
| إصدار Composer المُحلل == المتوقع | أن الثنائي الصحيح (2.9.5 مقابل 2.9.6) هو الذي تم تشغيله. |
يكون التشغيل "موافقًا" فقط عندما تنجح جميع الشروط الثلاثة. ينجح الاختبار الشامل عندما يكون التشغيل المتأثر موافقًا والتشغيل المُصحح غير موافق — وهي البصمة الدقيقة لثغرة حقيقية تم إصلاحها لاحقًا.
يتم بناء رابط المستودع الخبيث في writeComposerJson():
p4://127.0.0.1:1666:attacker_user;touch <marker> && echo '<runId>' > <marker>:client_test
تقسيمها:
p4://127.0.0.1:1666:attacker_user — رابط Perforce يبدو جيدًا (مضيف، منفذ 1666، مستخدم).;touch <marker> && echo '<runId>' > <marker> — أوامر الشل المحقونة. الـ ; في البداية تُنهي أمر p4 المقصود؛ touch تنشئ ملف العلامة، و echo '<runId>' > <marker> يكتب معرف التشغيل الفريد فيه حتى يتمكن إثبات المفهوم من تأكيد أن الحمولة (وليس عملية غير ذات صلة) أنتجت الملف.:client_test — نص تذييل للحفاظ على معقولية باقي تحليل الرابط.في برنامج التشغيل المتأثر، يتم احترام أحرف الشل الخاصة ويتم إنشاء ملف العلامة. في برنامج التشغيل المُصحح، يتم هروب القيمة/اقتباسها بشكل صحيح، لذلك يتم التعامل مع نفس السلسلة كبيانات خاملة ولا يظهر أي علامة.
ملاحظة: يستخدم إثبات المفهوم معرف تشغيل فريدًا ومختومًا بزمن ويكتب علامته داخل دليل مؤقت معزول، لذا فإن الحمولة غير ضارة وتنظف نفسها بنفسها بدلاً من أن تكون مدمرة.
2.9.5 (متأثر)2.9.6 (مُصحح)exec() بتشغيل cd … && php …). مصمم لـ Linux/macOS.composer.json أساسي في دليل المشروع (يُقرأ عند بدء التشغيل، ويُنسخ إلى كل تشغيل مؤقت، ويُستعاد بعد ذلك).لا تحتاج عمومًا إلى خادم Perforce مباشر: الثغرة تكمن في كيفية بناء Composer لسطر أوامر
p4، وتعمل الحمولة المحقونة قبل/حول أي اتصالp4حقيقي. قد يسجل Composer خطأ اتصال Perforce — هذا متوقع ولا يؤثر على إثبات ملف العلامة.
استنساخ / وضع إثبات المفهوم في دليل عمل.
توفير composer.json في نفس الدليل الذي يوجد به إثبات المفهوم. ملف صغير يكفي:
{
"name": "research/cve-2026-40176-poc",
"description": "Base manifest for the CVE-2026-40176 differential PoC",
"require": {}
}
الحصول على ثنائيي Composer ووضعهما حيث يتوقعهما إثبات المفهوم (القيم الافتراضية موضحة):
/usr/local/bin/composer-2.9.5.phar # متأثر
/usr/local/bin/composer-2.9.6.phar # مُصحح
يمكنك تنزيل إصدارات Composer محددة من الأرشيف الرسمي، على سبيل المثال:
curl -Lo /usr/local/bin/composer-2.9.5.phar https://getcomposer.org/download/2.9.5/composer.phar
curl -Lo /usr/local/bin/composer-2.9.6.phar https://getcomposer.org/download/2.9.6/composer.phar
إذا كانت مساراتك مختلفة، قم بتحرير وسيطتي المُنشئ في أسفل
CVE202640176Test.php.
php CVE202640176Test.php
تقوم الأداة المساعدة بتشغيل كلا إصداري Composer بدوره وتطبع الحكم النهائي. يتم استعادة composer.json الأصلي تلقائيًا حتى لو فشل التشغيل (يتم العمل في أدلة مؤقتة مؤقتة).
يحتوي المستودع على مختبر محوسب ينسخ البيئة تمامًا: بيئة تشغيل PHP CLI بالإضافة إلى إصداري Composer المثبتين في المسارات التي يتوقعها إثبات المفهوم، مع عزل شبكي كامل في وقت التشغيل.
docker compose run --rm poc
يبني هذا cve-2026-40176-lab:latest (تنزيل Composer 2.9.5 و 2.9.6 والتحقق من كل --version أثناء البناء) ويقوم بتشغيل الاختبار التفاضلي داخل حاوية غير مميزة وخالية من الاتصال الصادر.
ما يضمنه المختبر: