0x00 前言
7月11号Discuz ML被爆出存在任意代码注入漏洞,Discuz在国内的用户量还是很可观的,国外还没有去关注,从官方下载源码对漏洞的原理详细的分析了一下,源码地址(http://discuz.ml/download)
0x01 POC
1 | GET / HTTP/1.1 |
主要就是
1 | O2FL_2132_language=sc%27.phpinfo().%27; |
0x02 漏洞分析
这里分析Discuz ML v3.4源码,该漏洞主要是通过控制缓存文件的内容,之后缓存文件又被系统调用从而触发,根据POC可知是通过构造Cookie中language的值进行代码注入,在language中构造错误代码判断漏洞触发文件。
)都是require()和include()报错,也就是说是包涵的文件出了问题,到forum_index.php中查看一下
这里是调用缓存文件,根据报错信息可以知道导致报错的缓存文件是:data/template/sc’11_common_header_forum_index.tpl.php,很明显文件名中有部分片段是取自language的值,同时也就是说构造的POC会被植入到缓存文件中,跟进到template()中查看缓存文件的生成规则(function_code.php 644行)
很明显,缓存文件的命名规则由多部分组成,其中第一部分区自DISCUZ_LANG,根据前面的报错信息也可以知道,这个变量的值也就是Cookie中language字段的值,该函数最终返回DISCUZ_ROOT.$cachefile,可想而知,最终返回的便是缓存文件路劲用于文件包含,这里追溯一下DISCUZ_LANG(discuz_application.php定义)
DISCUZ_LANG的值取自于变量$lng,变量$lng的值取自于cookie language
很明显language字段的值没有经过任何过滤直接传到了变量$lng的值,直接用该字段对缓存文件进行命名,这也是导致该漏洞触发的直接原因。
接下来分析一下注入的代码是如何植入到缓存文件中的,定位到template类进行分析(class_template.php),在Discuz程序运行过程中,会读取template/default/common/目录下的默认模版
模版读取的内容传入到变量$template中,并对$template进行字符串替换操作
关键点在于变量$header
1 | $headeradd .= "|| checktplrefresh('$tplfile', '$fname', ".time().", '$templateid', '$cachefile', '$tpldir', '$file')\n"; |
将checktplrefresh也写入到缓存文件中,文件内容类型于
1 | <?php if(!defined('IN_DISCUZ')) exit('Access Denied'); |
结合上面的分析,其中变量$cachefile是我们可以控制的,也就是说控制生成的恶意变量名会被当作变量值写入到缓存文件中,别切恰好缓存文件会担子template()函数的返回值直接被包涵调用,这就太完美了,结合一下代码拼接,所以直接在language字段构造任意代码,例如sc'.phpinfo().'
(sc也可以不要),查看生成的缓存文件的内容。
由于代码包含的原因,所以注入到缓存文件中的恶意代码直接执行,其中首页就有包涵,全局搜索一下的话,应该有不少地方有进行包含可以直接利用。
0x03 修复建议
缓存缓文件名固定即可,加过滤的话也很容易被绕过。