Discuz!(v3.4 及以下) 任意文件删除漏洞分析
最近在做 CVE(或者说漏洞)的应急响应。原本应该是不看任何相关分析,仅凭漏洞的描述来搞 poc 以及 exp。但是以前没做过这类任务,所以这次打算先从复现做起。下次就直接怼源信息了。
Discuz!简介
简单来说,Discuz!是一个 BBS。很流行的那种。
漏洞前世
发现
2014 年 6 月 19,一个白帽子爆出了 Discuz 的一个任意文件删除漏洞,提交到 wooyun 平台上:
wooyun-2014-065513
分析
问题出在 source/include/spacecp/spacecp_profile.php
中:

这里的 $_GET['deletefile']
没有经过任何处理,直接遍历他的 $key
和 $value
,然后将 $space[$key]
拼接到一个路径中,带入了系统函数 unlink()
删除此文件。
这里的 $space[$key]
是通过用户的 uid
获取的用户信息的一些字段:

我们来看一下当程序运行到上面拼接路径时,$space
的具体内容:

$space
是一个数组,里面存了所有当前用户属性信息的字段和内容。
那么,因为 $_GET['deletefile']
是可控的,如果我们将 $_GET['deletefile']
的 $key
设置为 $space
中存在字段,比如 $space
中存在一个用户基本信息的情感状态的字段 affectivestatus
,默认是空的。
我们将 $_GET['deletefile']
的 $key
设置成 affectivestatus
,那么拼接后就成了:

其中 get('setting/attachdir')
为 .\Discuz\upload\data\attachment\profile
现在漏洞就显而易见了,因为这个 $space['affectivestatus']
的内容就是用户信息中的情感状况,我们提前先设置一下就行了啊,设置成我们想删除的任意文件,比如 ../../../111111.txt
:

为啥是 ../../../
?其实这里演示的是删 upload 下的文件,上面说过了 get('setting/attachdir')
的位置
第一步,我们先设置个人基本信息,将情感状况设置为你想删除的文件路径。
第二步,我们发送如下请求即可删除你设置的特定文件:

这里的 formhash
就是登陆后的一个 token
,可以在页面源代码中看到,这个 profilesubmit
必须为 true
才能进行信息修改的操作,此时 $key=affectivestatus
,看看 $space['affectivestatus']
的内容:

这个时候通过路径拼接就达到我们删除这个 111111.txt
的目的了,提交上述第二步的请求就可以删除根目录下的 111111.txt
了。
修复
简单的在漏洞存在的地方加了一个判断:

在删除之前判断要删除的内容的 formtype
是不是 file 类型,由于用户信息的字段的 formtype
都是非 file 类型的,所以修复后导致无法在此处删除文件了。
漏洞今生
三年后,在 2017 年 9 月 29 日,Discuz 官方再次修复了这个文件,通过对比分析补丁发现同样存在一个任意文件删除漏洞,漏洞原理和触发过程跟 2014 年的漏洞一模一样,我们来看看漏洞代码。
同样在文件 source/include/spacecp/spacecp_profile.php
中,有如下代码:


这里在上传文件的时候,如果上传成功,最后在倒数第二行代码里面:

也会进行一次删除操作,将 $space[$key]
拼接到路径后直接删除。
这里的 $space
前面已经分析过了,这个 $key
就是上传文件是遍历 $_FILES
变量中的 $key
,再上传时同样没有处理 $key
的内容,所以也是可控的。
那么漏洞利用原理就是一样了,只不过是在提前设置好用户信息为路径外,第二步需要上传一个文件,让流程走到上传文件这里。
第一步,我们先设置个人基本信息,将情感状况设置为你想删除的文件路径。
第二步,我们修改一下页面属性为 type=file
,然后来上传一个文件:

点击保存后,程序就会走到上传的地方,然后第一步设置的 ../../../111111.txt
文件就会被删掉。这时候的 $key 值:

这时候的 $space[$key]=$space['affectivestatus']
的值:
大家可能注意到前面有很多 if 判断,这里需要注意上传的时候只能上传图片类型的文件,否则在:

这会判断不通过,导致 continue,走不到下面的 unlink
。
修复
至于漏洞修复,官方直接将此文件中的删除操作全部删除:

EXP
用 python 简单写了一个 exp:
gayhub
后记
感觉官方的第一次修复有点敷衍,哪里漏了堵哪里。
说两点复现时候可能会踩到的坑:
使用
127.0.0.1
以及localhost
的时候可能会出现抱歉,您的请求来路不正确或表单验证串不符,无法提交
如果出现
非法字符已拦截
之类的,是formhash
错了这篇文章参考了绿盟的分析,加上了我自己的一些想法与实验。
来呀快活呀