
استغلال لثغرة CVE-2026-17544: كتابة خارج الحدود (OOB) في bcmath الخاصة بـ PHP تُحوَّل إلى RCE في الذاكرة فقط، مع تجاوز disable_functions و open_basedir عبر مُحلِّل خالٍ من الإزاحات (offset-free) في وقت التشغيل.
إثبات مفهوم مُسلَّح لـ CVE-2026-17544، وهي كتابة خارج الحدود في امتداد bcmath المُعاد كتابته في PHP (bc_str2num). يحوّل هذا الانهيار المعروف علنًا على أنه حرمان خدمة فقط (DoS) إلى أداة بدائية كاملة وعامة لتنفيذ تعليمات برمجية عن بُعد عبر الذاكرة فقط تتجاوز كلاً من disable_functions و open_basedir في الوقت نفسه.
للاستخدام البحثي / التعليمي المصرَّح به فقط. شغّل هذا فقط ضد أنظمة تملكها أو مخوَّل صراحةً لاختبارها.
bc_str2num باقتطاع الجزء الكسري عند scale يدوي، ويعيد قصّ الأصفار اللاحقة، لكنه لا يحدّث fractional_end. يتم تحديد حجم المخزن المؤقت وفقًا للطول بعد إعادة القص بينما تستخدم النسخة الطولَ قبل القص → كتابة صفرية موجَّهة خارج الحدود إلى كومة Zend MM.zend_string مجاور (مع الحفاظ على الطول) → استخدام بعد التحرير (use-after-free) ناتج عن عدم تطابق عدّاد المراجع → قراءة/كتابة نسبية عبر سلسلة ضخمة → قراءة مطلقة عشوائية آمنة تجاه الأخطاء → حلّ الرموز في زمن التشغيل → استدعاء دالة أصلية يعتمد على البيانات فقط بالكامل.zend_class_entry مزيفًا + function_table مضمّنًا + zend_function مزيفًا { handler = zif_shell_exec }، ثم تستدعيه كطريقة (method). يتم إرجاع مخرجات الأمر كسلسلة نصية وإيصالها إلى الاستجابة/الإخراج القياسي..data، والرمز المستهدف جميعها في زمن التشغيل عبر مسح الذاكرة — لذلك يعمل ملف واحد عبر جميع البِنى والتوزيعات.هذه أداة بدائية للهروب من العزل (sandbox) / ما بعد الاستغلال، وليست RCE تعتمد فقط على مدخلات عن بُعد.
| السيناريو | النتيجة |
|---|---|
يستطيع المهاجم بالفعل تنفيذ PHP (قشرة ويب، إلغاء تسلسل، حوض eval) لكنه محاصر بـ disable_functions + open_basedir | ✅ RCE أصلي (إثبات المفهوم هذا) |
| يكتفي التطبيق باستدعاء دالة bcmath على مدخلات مستخدم خام، مثل |
استدعاء bcmath واحد على مدخلات المهاجم يعطي كتابة صفرية واحدة خارج الحدود عمياء دون أي تغذية راجعة. يتطلب RCE الكامل تنفيذ PHP عشوائيًا لتنسيق الكومة (heap grooming)، وبناء بدائيات القراءة/الكتابة، وتشغيل المُحلِّل — ولا يمكن التعبير عن أيٍّ من ذلك كوسيط دالة. لذا فإن السقف الواقعي للتعرض عبر المدخلات فقط هو حرمان خدمة عن بُعد؛ أما تنفيذ التعليمات البرمجية فيتطلب سياق تنفيذ PHP قائمًا يحرّره إثبات المفهوم هذا من العزل.
الخلل موجود فقط في bcmath المُعاد كتابته (سلسلة PHP 8.4 / 8.5):
تم التحقق من طرف إلى طرف (uid=0، مع التقاط المخرجات) على PHP 8.4.23 وPHP 8.5.8، بمعمارية amd64، باستخدام الملف نفسه دون تعديل — تخطيط بنية Zend متطابق عبر 8.4 / 8.5.
bcmath..text إلى ترويسة ELF؛ وهذا آمن على أي ثنائي بتخطيط متصل. فقط بِنى -z separate-code الاصطناعية ذات الفجوات غير المعيّنة بمقدار 2 ميغابايت لا يمكن حلّها تلقائيًا بمسح أعمى (لم تُشاهَد في الإنتاج).exit() الخاص بكل طلب الخادم: php-fpm، أو Apache mod_php، أو الخادم المدمج مع PHP_CLI_SERVER_WORKERS>0.php exploit.php "id; uname -a"
انشره مثلًا كـ shell.php، ثم:
GET /shell.php?cmd=id
POST cmd=id
يتم التقاط مخرجات الأمر عبر zif_shell_exec وكتابتها في نص الاستجابة.
bccomp() القابل للاستغلال بحيث تقع الكتابة الصفرية خارج الحدود على عدّاد مراجع zend_string مجاور فقط (مع الحفاظ على الطول).zend_reference مزيف (عبر عدم المباشرة) إلى قراءة مطلقة عشوائية آمنة تجاه الأخطاء ولا تلمس أبدًا ترويسة العدّاد المرجعي للهدف..text مُسرَّب: تنقّل صفحةً صفحة وصولًا إلى توقيع ELF (القاعدة)، وحلّل ترويسات البرنامج للعثور على .data، ثم امسح .data بحثًا عن zend_function_entry الخاص بـ shell_exec الذي يشير معالجه إلى .text.zend_class_entry مزيفًا، وfunction_table مضمّنًا بفتحة واحدة (تجزئة صحيحة وسلسلة تصادم منتهية)، و مزيفًا يكون معالجه ؛ أفسد مؤشر الكائن الاستكشافي إلى الكلاس واستدعِ الطريقة. يتم إرجاع المخرجات وطباعتها.exploit.php — الاستغلال العام القائم على الذاكرة فقط (سطر أوامر + ويب).مقدَّم لأغراض البحث الأمني والتعليم. المؤلف غير مسؤول عن إساءة الاستخدام. لا تنشره ضد أنظمة غير مخوَّل لاختبارها.
bccomp($_POST['v'])| ❌ DoS / انهيار فقط |
| فرع PHP | قابل للتأثر |
|---|
| 7.x، 8.0 – 8.3 | لا (libbcmath قديم، وbc_str2num مختلف) |
| 8.4.0 – 8.4.23 | نعم |
| 8.5.0 – 8.5.8 | نعم |
| ≥ 8.4.24 / ≥ 8.5.9 | تم التصحيح |
zend_stringzend_internal_functionzif_shell_exec