
مختبر دوكر محلي يوضح CVE-2026-34234 هجوم تنفيذ الأوامر عن بعد غير المصادق عليه في مثبت ويب CtrlPanel. يتضمن حاويات ضعيفة ومُجرية النقاط، ونصوص برهان المفهوم (PoC)، وتحليل الجذر السببي لأغراض البحث الأمني والتحقق الدفاعي.
مختبر Docker محلي لعرض ثغرة CVE-2026-34234 في CtrlPanel.
يُقارن هذا المستودع بين:
vuln: CtrlPanel الإصدار 1.1.1 المثبت بواسطة digestpatched: CtrlPanel الإصدار 1.2.0 المثبت بواسطة digestالمختبر محلي فقط ويُقيّد الخدمات على 127.0.0.1.
CVE-2026-34234 هي ثغرة تنفيذ أوامر عن بُعد بدون مصادقة في مثبت CtrlPanel على الويب.
تنتج المشكلة عن خطأين مُتسلسلين:
install.lock.في هذا المختبر، الحاوية الضعيفة تنفّذ أمر إثبات غير ضار وتكتب مخرجاته داخل الحاوية. الحاوية المُصحّحة تستقبل نفس الطلب ولكنها لا تنشئ ملف الإثبات.
النتيجة المُتوقعة:
الضعيفة => تم إنشاء ملف الإثبات
المصححة => لا يوجد ملف إثبات
1.1.1الملف الأصلي الضعيف:
public/installer/src/functions/shell.php
الكود الأعلى ذو الصلة في الإصدار 1.1.1:
function run_console(string $command, ...) {
$path = dirname(__DIR__, 4);
$handle = proc_open("cd '$path' && bash -c 'exec -a ServerCPP $command'", ...);
}
المشكلة:
run_console() يقبل سلسلة أمر واحد للصدفة.bash -c.الملف الأصلي الضعيف:
public/installer/src/forms/pterodactyl.php
السلوك الأعلى ذو الصلة في الإصدار 1.1.1:
run_console("php artisan settings:set 'PterodactylSettings' 'panel_url' '$url'", ...);
run_console("php artisan settings:set 'PterodactylSettings' 'admin_token' '$key'", ...);
run_console("php artisan settings:set 'PterodactylSettings' 'user_token' '$clientkey'", ...);
المشكلة:
url و key و clientkey تأتي من بيانات POST للمثبت.الإعلان الأمني ينص على أن public/installer/index.php كان يتحقق من install.lock فقط بعد تحميل/تنفيذ منطق نماذج المثبت. هذا جعل معالجات المثبت قابلة للوصول حتى على نُسخ مُثبتة بالفعل.
الإصلاح ينقل فحص install.lock قبل تحميل معالجات النماذج.
السلوك المُصحّح:
if (file_exists('../../install.lock')) {
exit("تم الانتهاء من التثبيت بالفعل. يرجى حذف ملف 'install.lock' لإعادة التثبيت");
}
الملف الأصلي المُصحّح:
public/installer/src/functions/shell.php
الكود الأعلى ذو الصلة في الإصدار 1.2.0:
function run_console(array $command, ...): string {
$cwd = $cwd ?? $path;
$handle = proc_open($command, $descriptors, $pipes, $cwd, null, $options);
}
لماذا يُصلح هذا المشكلة:
run_console() الآن يقبل مصفوفة على غرار argv.$() يبقى كمدخل حرفي بدلاً من تركيب الصدفة.السلوك المُصحّح للنموذج في الإصدار 1.2.0 يستخدم تنفيذ الأوامر بنمط المصفوفة:
run_console(['php', 'artisan', 'settings:set', 'PterodactylSettings', 'panel_url', $url], ...);
run_console(['php', 'artisan', 'settings:set', 'PterodactylSettings', 'admin_token', $key], ...);
run_console(['php', 'artisan', 'settings:set', 'PterodactylSettings', 'user_token', $clientkey], ...);
127.0.0.1:8081 -> CtrlPanel الضعيفة 1.1.1
127.0.0.1:8082 -> CtrlPanel المُصحّحة 1.2.0
127.0.0.1:9100 -> API Pterodactyl وهمية
الخدمات:
vuln: CtrlPanel حقيقية 1.1.1patched: CtrlPanel حقيقية 1.2.0fake-api: API Pterodactyl محلية وهمية تُستخدم فقط لتلبية فحوصات المثبتmysql_vuln / mysql_patched: مثيلات MariaDB منفصلةredis_vuln / redis_patched: مثيلات Redis منفصلةالمختبر لا يُعدّل كود مصدر تطبيق CtrlPanel.
ملفات Dockerfile فقط تُغلف نقطة الدخول الأصلية للحاوية لتطبيع أذونات وقت تشغيل Docker Desktop من أجل:
/var/www/html/storage
/var/www/html/bootstrap/cache
بعد إصلاح الأذونات، الغلاف ينفذ نقطة الدخول الأصلية للمنتج.
إثبات المفهوم الرئيسي:
poc/poc_http_only.py
الخصائص:
docker execid، whoami، hostnameالبرنامج المساعد:
poc/poc_lab.py
الغرض:
docker compose execملف الإثبات داخل حاوية التطبيق:
/var/www/html/storage/logs/cve_2026_34234_proof.txt
ابدأ من حالة مختبر نظيفة:
docker compose down -v --remove-orphans
docker compose up -d --build
انتظر حتى تصبح حاويات التطبيق جاهزة، ثم شغّل:
python3 poc/poc_lab.py
المخرجات المتوقعة:
== اختبار الضعيفة ==
proof_exists: True
النتيجة: PASS expected_proof=True
== اختبار المُصحّحة ==
proof_exists: False
النتيجة: PASS expected_proof=False
[+] تم الوصول إلى النتيجة المتوقعة:
الضعيفة => تم إنشاء ملف الإثبات
المُصحّحة => لا يوجد ملف إثبات
أرسل إثبات المفهوم عبر HTTP فقط إلى الهدف الضعيف:
python3 poc/poc_http_only.py --target http://127.0.0.1:8081
تحقق من الإثبات يدويًا:
docker compose exec vuln sh -lc 'cat /var/www/html/storage/logs/cve_2026_34234_proof.txt'
الإثبات المتوقع:
uid=1000(laravel) gid=1000(laravel) groups=1000(laravel)
laravel
<اسم_مضيف_الحاوية>
نفّذ نفس الطلب ضد المُصحّحة:
python3 poc/poc_http_only.py --target http://127.0.0.1:8082
تحقق من سلوك المُصحّحة:
docker compose exec patched sh -lc 'test -f /var/www/html/storage/logs/cve_2026_34234_proof.txt && cat /var/www/html/storage/logs/cve_2026_34234_proof.txt || echo "لا يوجد ملف إثبات"'
المتوقع:
لا يوجد ملف إثبات
إزالة الحاويات والشبكات وأحجام المختبر:
docker compose down -v
هذا المستودع يُقدّم لأغراض البحث الأمني التعليمي والتحقق الدفاعي فقط.
جميع العروض التوضيحية تهدف للتشغيل داخل بيئة المختبر المحلي Docker المُقدّمة. إثبات المفهوم يتجنب الإجراءات التدميرية، الثبات، سرقة بيانات الاعتماد، استخراج البيانات، والاستهداف في العالم الحقيقي.
لا تستخدم هذا المشروع ضد أي نظام بدون إذن صريح. المؤلف غير مسؤول عن سوء الاستخدام أو الضرر الناتج عن هذه المادة.