善变PDF:利用浏览器渲染差异进行攻击
想象一下,某公司CEO收到一封包含PDF发票文件的邮件。在Safari和MacOS Preview中显示的总价为399英镑。经批准后,发票发送到使用Windows操作系统的会计部门。然而,当同一个PDF文件在Google Chrome或Google Drive中打开时,价格变为999英镑。
在本文中,我们将展示如何创建滥用小部件注释的混合PDF以产生渲染差异,并分享代码以便您生成自己的PDF。这项研究受到Konstantin Weddige的博客文章"Kobold Letters"的启发。
浏览器PDF渲染差异
每个主要浏览器都有自己渲染PDF文件的方法。Google Chrome使用名为PDFium的集成PDF查看器,Safari使用自己的PDF渲染引擎,而Firefox使用PDF.js。由于PDF渲染差异,同一个PDF文件在不同浏览器中可能显示不同。例如,交互式表单字段的外观在浏览器之间有所不同。
Google Chrome全面支持交互式表单字段和小部件注释,在用户交互时会动态将显示文本从注释值更新为表单字段的默认值。然而,Firefox和Google Drive预览都优先考虑小部件注释,完全忽略默认值。相比之下,Safari的PDF渲染引擎完全绕过小部件注释,仅显示默认值。
构建概念验证
为了构建概念验证,我们将使用org.apache.pdfbox Java库。请注意,即使通过手动文件修改也可以实现相同的结果。我们的交互式表单应至少有一个输入文本字段及其注释。该字段的纯文本值可以是任何字符串,例如£399。此值将在不支持表单的PDF阅读器(如Safari和MacOS Preview)中显示。
有趣的是,org.apache.pdfbox.pdmodel.interactive.form.PDTextField#setValue方法也尝试更新视觉外观,除非PDAcroForm.getNeedAppearances()为true。但是,我们不会使用默认外观,而是使用小部件注释渲染自己的外观。
小部件注释是添加到PDF文档中的对象,用于提供附加信息或交互元素而不改变原始内容。小部件注释表示交互式PDF表单中表单字段的外观。它将显示文本£999而不是默认值。伪代码可能如下所示:
|
|
请注意,注释可以包含任何文本,理论上没有什么可以阻止您覆盖整个页面。完整文本可在https://github.com/PortSwigger/research-labs/tree/main/pdf-rendering-discrepancies找到。
Safari渲染PDF: Google Chrome和Drive预览渲染不同的总价: Firefox与Google Chrome一致:
有趣的是,ChatGPT不支持注释。如果您要求它分析发票,它将返回以下内容: PDF文件是Carlos Montoya的发票,包含以下详细信息: 发票编号:1 签发日期:2001年1月1日 到期日期:3001年1月1日 项目: 项目:L33T皮夹克 数量:1 单价:£399 总计:£399
最后说明
PDF文件渲染过程复杂且模糊。在将文件发送到会计部门付款或授予聊天助手访问邮箱权限时请谨慎。您可以在Github上找到Fickle pdf文件。