【漏洞挖掘Tips】将JS伪造为PDF的方法
[TOC]
什么是PDF/JS Polyglot文件?
Polyglot文件指的是一个文件同时满足多种文件格式的解析规则,看似是合规的某类文件(如PDF),实则包含另一类可执行代码(如JS)。PDF/JS Polyglot文件就是利用PDF和JS解析机制的差异,让文件在PDF阅读器中正常显示,却能在浏览器以脚本形式加载时执行恶意JS代码,从而绕开文件上传过滤、触发XSS等攻击。
技术原理
制作此类 Polyglot 主要有三种方式:
- 方法一:头部偏移容错
- 方法二:字符串/注释包裹法
- 方法三:多容器嵌套(HTML/PDF Polyglot)
虽然是三种方法,但是在核心原理上是一致的,都是利用的两种格式在解析机制上的差异和容错性造成的,只不过不同的路径被归纳为了不同的方法。
头部偏移容错
头部偏移容错是最常见的也是最直接的制造此类 Polyglot 的方式。
原理:
一般而言标准的 PDF 解析器(比如 Adobe Acrobat、Chrome PDF Viewer)通常不强制要求 %PDF-1.x 魔法头(Magic Bytes)必须位于文件的第 0 字节。它们通常会扫描文件的前 1024 字节来寻找这个头。
而 JavaScript 引擎特性:JS 是从头开始执行的。
这种两者之间的差异就是我们操作的空间
构造方法:
在文件的最开头编写有效的 JavaScript 代码,并在 1024 字节内(通常紧接在 JS 代码后或被注释包裹)放置 PDF 头。
示例:
1 | var a = "Hello"; // 有效的JS代码 |
如果这个时候服务器仅检查文件扩展名是 .pdf,但内容被浏览器以 <script src="file.pdf"> 加载,JS 就会执行。
字符串/注释包裹法
这个方法的原理是利用一种语言的“注释”或“字符串”语法来隐藏另一种语言的代码。
方法 1:PDF 在 JS 字符串/注释中
如上一个例子所展示的,将整个 PDF 的二进制内容放入 JavaScript 的块注释 /* ... */ 或一个巨大的字符串变量 var pdf = "..."; 中。
难点:PDF 中不能包含会破坏 JS 语法的字符(如未转义的引号或 */ )。这通常需要对 PDF 进行编码或精心构造(比如避免在 PDF流中使用 */ )。
方法 2:JS 在 PDF 注释中
PDF 使用 % 字符作为单行注释。
可以在 PDF 对象之间插入 % 开头的行,并在其中放入 JS 代码(虽然这对直接执行 JS 帮助不大,常用于HTML/PDF 混合利用)。
示例:
1 | %PDF-1.4 |
多容器嵌套
相比较于前两种而言,这是一种更高级的组合,通常引入 HTML 作为中间层,因为浏览器解析 HTML 非常宽容。
原理:
- 先去构造一个文件,它既是有效的 PDF,又是有效的 HTML。
- 然后在 HTML 中包含
<script>标签来执行 JavaScript。
构造:
- 利用文件开头是 PDF 头(或 HTML 能够忽略的字节)。
- 然后再去利用 HTML 的容错性,将 PDF 的二进制数据视为“乱码”文本显示,或者说通过 CSS 隐藏这些。
这个时候文件可以绕过某些上传过滤器(看起来像 PDF,毕竟我们花了么多功夫去构建),但当受害者访问该链接时,如果是以 text/html 渲染,就会执行其中的 XSS Payload。
工具
除了上述我们提到的几种方法去手动构建外,可以使用工具自动构建。
Mitra
Mitra 是一个基于 Python 的脚本,能够自动分析两个文件的格式,并尝试将它们合并为一个“多语言文件”。
GitHub 地址: https://github.com/corkami/mitra
核心原理: 和上述介绍的一样,利用不同文件格式在解析逻辑上的差异(如头部偏移、注释符号、尾部数据忽略等)将两个文件“寄生”或“堆叠”在一起。
安装
1 | # 1. 克隆仓库 |
基础使用 (生成 PDF/JS Polyglot)
假设有一个正常的 PDF 文件 document.pdf 和一个包含恶意代码的 JavaScript 文件 payload.js 。
准备工作
我们先创建一个简单的 JS payload 文件 (例如 payload.js ):
1 | // 简单的测试 payload |
然后继续调用 Mitra 去生成
1 | python mitra.py document.pdf payload.js |
这样就可以不用自己去考虑怎么去构建了




