最近几个月,爆出来了几个 pdf 相关漏洞:
而这两个漏洞给出的 poc 都是简单的字符串模版替换,比如:
但是呢,有时会有一些特殊需求,我需要将正常的 pdf 文件转为这种“恶意”文档,这就比较麻烦了,我们需要了解 PDF 文件格式,然后才能在正常的 PDF 文件中加入 exp。
PDF 文件格式
先来看看 PDF 文件格式,我们以这个 poc_generalized_CVE-2024-4367 中的 PDF 文档为例。
其结构总体来说还是比较清晰的,pdf 文件解析的入口便是这个
trailer directory
与
startxref
。
可以参考 pypdf2 pdf-format 中解释的,
trailer
中的
/Root
便是文档的目录结构根节点,对应到图中的序号为
1
,也就是
Body Section
中的:
1 0 obj
这个条目。
而
Body Section
中的这些条目是怎么定位的呢?关键在于这个
startxref
。
startxref 指定了
xref
表的偏移:
这个
xref
表中定义了 pdf 文档节
点的数量以及每个节点的偏移(具体的每一项是什么意思可以参考文档,这里不赘述)。
这些树状节点便是 pdf 文档的 "body" 了:
其格式为: (注:pdf 结构中空格与回车换行基本等价,都是分隔符)
counter generationnumber << the_object >> endobj
object body
的格式其实就是“键值对”,但是不同于我们熟知的
{"key": "value"}
这种形式,pdf 中的形式为
/Key /Value
。
Key
部分一般是
Name Object
,
Value
可以是:
-
Boolean Object
-
Numberic Object
-
String Object
-
Name Object
-
Array Object
-
Dictornary Object
-
Stream Object
-
Null Object
-
Indirect Object
具体可参考 adobe 对 PDF 文件格式的定义:PDF_ISO_32000-2.pdf 中的
7.3
节。
手动修改一个正常的 PDF 文档
CVE-2024-4367
手动改起来比较麻烦,这里以 Foxit 的 pdf_exploit 为例,
这个“漏洞”所利用的其实就是
PDF
中的正常文档的格式:
参考 PDF_ISO_32000-2 中的 7.7.2 节 "Document catalog dictionary":
也就是说,我们只要在
/Catalog
节点中,添加
/OpenAction
即可。
随便找个 PDF 文件,尝试修改它。这里简单创建一个 PDF:
从
trailer dictionary
中可以看到
Root
节点编号为
9
,这个
Root
节点的
Type
便是
Catalog
。我们只要在这个节点里加上
/OpenAction
即可。
为了方便看,简单格式化了一下这部分。
改完这里后,其实原始文档中有很多偏移都需要进行相应调整,如下图所示,
xref
自身的偏移也错误了、
xref
表中的第9条以后的条目的偏移也错误了。
不过,大部分常用的pdf文件解析器并没有完全的依靠偏移地址,因为即便没有进行偏移修复,这个 pdf 文档还是可以被解析。这也就可以解释了,为啥
很多 poc 都是直接用的模版变量,没有去修正偏移
。
不过呢,这种 pdf 毕竟不是完全“合格”的,在遇到一些只使用偏移来定位节点的库去解析时,就会发现问题,比如说: https://github.com/ledongthuc/pdf.git
方便的将exp集成到指定的PDF
其实如上面写的,忽略偏移直接修改相关节点,虽然会导致文件有点“不合格”,但总的来说还是能用的。
foxit
这个例子还比较简单,不需要多加什么节点,只要在
/Catalog
中添加
/OpenAction
属性就行了。
但是对于
CVE-2024-4367
来说,就比较麻烦了。如那个 poc 中所展示的,我们需要添加相应的字体节点,并在
/Page
下的
/Resources
中声明该字体,然后在
/Content
中添加文字内容,使用该字体。大致关联关系下图所示:
逻辑比较复杂,手动直接编辑文件可太麻烦了。那么有没有比较合适的库可以直接用呢?找了找 pdf 相关的一些解析库,还真有一个非常好用的库: pypdf。
A pure-python PDF library capable of splitting, merging, cropping, and transforming the pages of PDF files