
يوثّق CVE-2026-65320، وهو اجتياز مسار tar-slip في untar_dir() الخاص بـ fastcore، مع إثبات مفهوم غير ضار يوضح الكتابة التعسفية للملفات وتنفيذ التعليمات البرمجية.
untar_dir()الخطورة: حرجة، CVSS 3.1 9.8
المتجه (v3.1): CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
المتأثر: fastcore <= 2.2.30
تم الإصلاح في: لم يتم الإصلاح وقت كتابة هذا التقرير
CWE: CWE-22 (التقييد غير الصحيح لاسم المسار إلى دليل محظور، 'اجتياز المسار')
المكوّن: fastcore.xtras.untar_dir() → fastcore.xtras._unpack() → shutil.unpack_archive()
بيئة التشغيل عالية الخطورة: Python < 3.14 (يجعل Python 3.14 مرشّح tar الآمن data هو الافتراضي)
أبلغ عنه: Rahul Karne
CNA: VulnCheck
fastcore.xtras.untar_dir(fname, dest) هي دالة مساعدة موثّقة تقوم بفك ضغط أرشيف tar "إلى dest".
داخليًا، تقوم بتمرير الأرشيف إلى shutil.unpack_archive() من المكتبة القياسية دون مرشّح استخراج، ودون التحقق من مسارات أعضاء الأرشيف، ودون أي فحص احتواء بعد الاستخراج.
ونتيجة لذلك، يمكن لأرشيف TAR يحتوي أعضاؤه على تسلسلات اجتياز ../ أو مسارات مطلقة أن يكتب ملفات خارج الدليل الذي طلب المتصل من fastcore الاستخراج إليه.
المتصل الذي يتوقع بشكل معقول أن untar_dir(fname, dest) ستحصر كل شيء داخل dest يحصل بدلاً من ذلك على كتابة ملفات عشوائية في أي مكان يمكن للعملية الكتابة فيه.
كتابة ملفات عشوائية تحت صلاحية العملية التي تستدعي untar_dir().
اعتمادًا على ما يتم استبداله، يمكن أن يؤدي ذلك إلى:
يوضّح إثبات المفهوم سلسلة الكتابة → الاستيراد → تنفيذ التعليمات البرمجية كاملة من البداية إلى النهاية، بالكامل داخل دليل تجريبي غير ضار.
fastcore هي تبعية أساسية في منظومة fast.ai بأكملها، بما في ذلك:
fastainbdevghapiوهي تتلقى عشرات الملايين من التنزيلات شهريًا.
untar_dir() هي البدائية الأساسية للاستخراج وراء سير العمل الشائع "تنزيل أرشيف، ثم فك ضغطه"، والذي يتبع نفس النمط العام لـ untar_data في fastai.
أي مسار برمجي يغذّي untar_dir() بأرشيف لا تكون محتوياته موثوقة بالكامل يكون معرّضًا للخطر.
توجد التعليمات البرمجية المعرّضة للخطر في fastcore/xtras.py:
def _unpack(fname, out):
import shutil
shutil.unpack_archive(str(fname), str(out)) # <-- no filter, no validation
ls = out.ls()
return ls[0] if len(ls) == 1 else out
def untar_dir(fname, dest, rename=False, overwrite=False, uid=-1, gid=-1):
"untar `file` into `dest` ..."
import tempfile, shutil
dest = Path(dest)
with tempfile.TemporaryDirectory() as d:
out = Path(d) / remove_suffix(Path(fname).stem, '.tar')
out.mkdir()
...
src = _unpack(fname, out) # extraction escapes `out` here
...
shutil.move(str(src), dest)
...
return dest
تنشئ untar_dir() دليل استخراج مؤقت داخلي:
<tempdir>/<random>/<archive-stem>/
ثم تستدعي _unpack()، التي تمرّر الأرشيف مباشرة إلى:
shutil.unpack_archive()
بالنسبة لأرشيفات TAR، يستدعي هذا في النهاية tarfile.extractall().
على Python < 3.14، يكون سلوك الاستخراج الافتراضي هو fully_trusted، مما يعني أنه يمكن احترام الأعضاء المتجاوزة.
على سبيل المثال، عضو أرشيف مثل:
../../../some/other/dir/file
يُكتب نسبةً إلى دليل الاستخراج وبالتالي يمكنه الهروب منه.
لا شيء في fastcore:
filter="data" حيث يكون مدعومًا....تتعامل untar_dir() مع shutil.unpack_archive() كما لو كانت مستخرج أرشيف آمنًا ومعزولاً.
لكنها ليست كذلك.
تحذّر وثائق مكتبة Python القياسية من أن استخراج الأرشيفات غير الموثوقة قد ينشئ ملفات خارج الوجهة المطلوبة، وتوصي بترشيح الاستخراج الآمن لأرشيفات TAR.
لا تمرّر fastcore مرشّح استخراج مناسبًا ولا تنفّذ حارس احتواء مكافئًا لإصدارات Python التي تدعمها.
كما أنها لا تحذّر المتصلين بـ untar_dir() من هذا السلوك الحساس أمنيًا.
يمكن أن تحتوي أعضاء TAR على سلاسل مسارات عشوائية.
على إصدارات Python المتأثرة، لا يقوم tarfile.extractall() بتحييد تسلسلات اجتياز .. تلقائيًا بشكل افتراضي.
لذلك، فإن كتابة عضو متجاوز نسبةً إلى دليل الاستخراج المؤقت في fastcore كافية للهروب من ذلك الدليل والكتابة في أي مكان تملك العملية صلاحية الكتابة فيه.
البدائية الموثوقة هي الاجتياز النسبي مثل:
../../../target/file
وهذه هي التقنية المستخدمة في إثبات المفهوم.
المدخل الخطير هو محتويات الأرشيف، وليس مسار الوجهة الذي اختاره المطوّر.
غالبًا ما يتم الحصول على الأرشيفات من مواقع خارجية أو شبه موثوقة، بما في ذلك:
لذلك، أي خدمة أو أداة تنزّل أرشيفًا من مصدر غير موثوق أو شبه موثوق ثم تعالجه باستخدام untar_dir() قد تكون قابلة للوصول.
يتضمن إثبات المفهوم أيضًا نسخة تقدّم الأرشيف المُصمَّم من نقطة نهاية HTTP يتحكم بها المهاجم لتوضيح مسار التسليم هذا.
يتطلب الاستغلال الناجح:
أن يستدعي التطبيق fastcore.xtras.untar_dir() على أرشيف تكون محتوياته متأثرة بالمهاجم، مثل أرشيف مرفوع أو منزّل أو غير موثوق بأي شكل آخر.
أن تستخدم بيئة التشغيل Python < 3.14، أو أي إعداد آخر لا يُفرض فيه مرشّح استخراج TAR آمن.
للتصعيد من كتابة ملفات عشوائية إلى تنفيذ التعليمات البرمجية، يجب أن يستورد أو يحمّل التطبيق لاحقًا ملفًا من موقع يمكن الوصول إليه عبر الاجتياز، مثل:
تتطلب كتابة الملفات العشوائية وتعديل الإعدادات/البيانات الشرطين 1 و2 فقط.
يستدعي poc_fastcore_cna_demo.py واجهة fastcore.xtras.untar_dir() الحقيقية.
العرض غير ضار عن قصد.
كل ملف ينشئه إثبات المفهوم يبقى داخل دليل تجريبي واحد يُحدَّد باستخدام:
--demo-root
لا يعدّل إثبات المفهوم ملفات نظام حقيقية ولا يصل إلى خدمات سحابية أو بيانات اعتماد.
يطبع تفاصيل البيئة والتعليمات البرمجية المعرّضة للخطر الخاصة بـ _unpack() و untar_dir().
ينشئ تخطيطًا تجريبيًا يحتوي على:
service_app/plugins/
ينشئ:
attacker_supplied_upload.tar
يحتوي على أعضاء أرشيف مصمّمة للإشارة خارج جذر الاستخراج المقصود، بما في ذلك أعضاء الاجتياز و:
service_app/plugins/startup_hook.py
def auto_extract_uploaded_archive(received_archive):
return untar_dir(
received_archive,
intended_root,
overwrite=True
)
يتحقق من أن الملفات كُتبت خارج دليل الاستخراج المقصود.
يحاكي إعادة تحميل الخدمة باستيراد الملف المكتوب من الأرشيف:
startup_hook.py
ينشئ خطاف بدء التشغيل غير الضار:
SERVICE_RELOAD_MARKER
يوضّح هذا السلسلة الكاملة:
Attacker-controlled archive
↓
Path traversal during extraction
↓
Arbitrary file write
↓
Write into importable / auto-loaded location
↓
Application loads attacker-controlled file
↓
Code execution
ثبّت الحزمة المتأثرة:
pip install fastcore
تم تأكيد المشكلة عبر:
fastcore 2.2.30
يمكن تشغيل العرض مقابل أي من:
fastcore المثبّتة عبر pip--sourceتبقى جميع كتابات إثبات المفهوم داخل الدليل المحدد عبر --demo-root.
نظّف أي مخرجات سابقة لإثبات المفهوم:
python poc_fastcore_cna_demo.py --demo-root ./poc_fastcore --clean
شغّل العرض:
python poc_fastcore_cna_demo.py \
--demo-root ./poc_fastcore \
--source latest \
--no-pause
مثال على مخرجات مختصرة:
fastcore version: 2.2.30
Outside marker exists after extraction? True
Is outside marker inside intended extraction root? False
Relative traversal marker exists after extraction? True
Is relative traversal marker inside intended extraction root? False
Service plugin file exists after extraction? True
Service reload marker exists? True
POC WORKED: fastcore extracted attacker-controlled tar members outside the intended root.
على إصدارات Python المدعومة، استخدم مرشّح استخراج آمن مثل:
filter="data"
مع shutil.unpack_archive() أو عملية استخراج tarfile المقابلة.
يجب فحص كل عضو أرشيف قبل الاستخراج.
ارفض:
..يجب أيضًا تحليل أهداف الروابط والتحقق منها قبل الاستخراج.
حلّل كل مسار وجهة قبل الكتابة وتحقق من أنه يبقى تحت جذر الاستخراج المقصود.
مفاهيميًا:
resolved_member_path
↓
must remain inside
↓
resolved_extraction_root
يجب أن يفشل الاستخراج إذا هربت الوجهة المحلّلة من جذر الاستخراج.
يجب أن تغطي اختبارات الانحدار على الأقل:
../ traversal
absolute paths
Windows drive-letter paths
UNC paths
symbolic links
hard links
وثّق بوضوح ما إذا كانت untar_dir() مخصصة لمعالجة الأرشيفات غير الموثوقة بأمان.
إذا كان الاستخراج غير الآمن مدعومًا عن قصد، فيجب أن يظل السلوك الآمن هو الافتراضي.
يجب أن يتطلب السلوك غير الآمن موافقة صريحة بدلاً من الثقة الصامتة في محتويات الأرشيف.
حتى يتم إصدار إصلاح على مستوى الحزمة:
untar_dir().العيب التقني الأساسي هو ثغرة كتابة ملفات عشوائية ناتجة عن اجتياز مسار الأرشيف.
ومع ذلك، تعتمد الخطورة النهائية على بيئة النشر وكيفية تعريض untar_dir().
قد يقترب متجه تمثيلي من:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
النتيجة:
9.8 — Critical
إذا كان الاستغلال يتطلب بدلاً من ذلك أن يقوم المطوّر بتنزيل أرشيف واستخراجه يدويًا، فقد يكون تفاعل المستخدم وتعقيد الهجوم أعلى.
وبالتالي ستكون درجة CVSS الناتجة أقل بشكل ملموس.
يجب مراعاة عاملين مهمين عند تقييم المشكلة.
هذه حالة من فئة ثغرة استخراج TAR غير الآمن المعروفة منذ زمن طويل والمرتبطة بـ:
CVE-2007-4559
قدّمت إصدارات Python الحديثة سلوك استخراج أرشيف أكثر أمانًا.
يجعل Python 3.14 مرشّح الاستخراج الآمن data هو الافتراضي.
لذلك، فإن بيئة التشغيل المتأثرة الأساسية هي Python < 3.14.
ومع ذلك، تظل بيئات التشغيل هذه منتشرة على نطاق واسع.
تصبح الثغرة قابلة للاستغلال عندما يزوّد المتصل untar_dir() بأرشيف تكون محتوياته يتحكم بها المهاجم أو غير موثوقة بأي شكل آخر.
لذلك يعامل هذا التقرير محتويات الأرشيف كحدود الأمان غير الموثوقة.
يجب أن تفشل دالة استخراج أرشيف قوية بأمان بغض النظر عن كيفية الحصول على الأرشيف.
استبدل تواريخ العناصر النائبة أدناه بتواريخ الإفصاح الفعلية.
YYYY-MM-DD — تم الإبلاغ عن الثغرة للمشرفين.YYYY-MM-DD — رد المورّد / إقرار / لا رد.2.2.30)؛ بقيت تعليمات الاستخراج البرمجية دون تغيير.تم اكتشافها والإبلاغ عنها بواسطة Rahul Karne.
وثائق untar_dir() في fastcore
https://fastcore.fast.ai/xtras.html
مصدر xtras.py في fastcore
https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/xtras.py
fastcore على PyPI
https://pypi.org/project/fastcore/
وثائق shutil.unpack_archive() في Python
https://docs.python.org/3/library/shutil.html#shutil.unpack_archive
مرشّحات استخراج tarfile في Python
https://docs.python.org/3/library/tarfile.html#extraction-filters
PEP 706 — مرشّح لـ tarfile.extractall
https://peps.python.org/pep-0706/
CWE-22 — التقييد غير الصحيح لاسم المسار إلى دليل محظور
https://cwe.mitre.org/data/definitions/22.html
CVE-2007-4559 — فئة ثغرة استخراج TAR غير الآمن
https://nvd.nist.gov/vuln/detail/CVE-2007-4559
يوثّق هذا المستودع اكتشافًا أمنيًا بإفصاح منسّق ويوفّر إثبات مفهوم غير ضار ومكتفٍ ذاتيًا.
يكتب إثبات المفهوم فقط داخل دليل --demo-root المحدد من المستخدم ولا ينفّذ أي إجراءات مدمّرة.
أي وظائف شبكية مضمنة في العرض تقتصر على عرض محلي اختياري.
هذه المواد مقدّمة لأغراض البحث الأمني الدفاعي والتعليمي.
استفسارات الإعلام: [email protected]. إثبات المفهوم الكامل (خادم المهاجم، أرشيف الاجتياز، تطبيق الضحية) وتفاصيل تقنية إضافية متاحة عند الطلب.