之前PHPCMS V9.6.0被爆出来一波SQL注入个getshell的漏洞,官方修复了(典型的指哪修哪)并且发布了V9.6.1。但是并没有修复完全,又被搞出来一个任意文件下载的漏洞,此漏洞Payload同样可以绕过WAF检测。
漏洞分析
这个漏洞的套路跟之前的那个SQL注入漏洞一样。
这次我们顺着来看这个漏洞产生的过程。
漏洞触发点在文件/phpcms/modules/content/down.php,来看init函数:
通过GET获取到$a_k参数内容,然后$a_k参数内容进入到sys_auth函数进行解密,说明我们传入的$a_k是提前已经加密的内容了,这里我们不用关系他到底是怎么解密的。
我们继续看parse_str($a_k);,这里的parse_str函数有一个Trick:
Parse_str函数会自动对传入的值将其根据&分割,然后解析到具体变量并注册变量,并且对内容进行URL解码操作。
比如我们我们传入字符串’id=123%27%20and%201=1%23’,经过parse_str函数后就变成了id=123’ and 1=1#,就是id变量的内容为123’ and 1=1#。
继续往下看有一个$f变量且不能为空,这里正好通过parse_str处理后注册了$f变量,说明$f变量的内容使我们可控的。
继续到下面:
这里判断你的$f是不是有那一堆非法的后缀,或者使用’:\’,或者使用’..’,只要匹配到其中一种就是非法的。
然后在判断是不是外链文件http://或者ftp://,或者未使用’://’,系统生成一个$pc_auth_key,以这个$pc_auth_key为auth_key加密一个拼接了各种参数的url,上面的变量$f也在里面,然后生成一个$downurl,也就是下载文件的链接。
这里我们跟进这个下载文件的地方,/phpcms/modules/content/down.php,download函数:
这列将GET获取的$a_k变量的内容进行解密,解密时使用$pc_auth_key为auth_key,跟上面在init函数里面加密使用的同一个auth_key,这里加密解密就对应起来了。
然后变量$a_k通过一次safe_replace函数处理,再次通过parse_str函数处理。
我们继续往下看:
这列继续对$f变量进行后缀和特殊字符的判断。
然后将$s和$f拼接起来,再来判断fileurl的后缀。
如果fileurl是远程文件就直接跳转了,如果不是就继续else里面的处理。
首先获取文件后缀,然后加上一个日期为文件名,最后将fileurl中的’<’和’>’替换为空。
最后将fileurl既文件路径,和filename既文件名传入到file_down函数进行下载。
这里只是一个简单的下载,没有任何处理。
所以一路走下来,我们可控的参数进入到了fileurl既文件路径和filename既文件名里面。
大家可以看到在文件路径里面判断了很多次要下载的文件后缀,不能下载php等文件,但是注意到上面以一个替换操作:将fileurl中的’<’和’>’替换为空。
问题就在这里了,如果我们输入一个ph,一个>p,然后相加就是ph>p,经过替换后就变成了php,而在这个过程中,正好有$s和$f拼接的过程:
$s=’test.ph‘ + $f=’>p’ = $fileurl=’test.ph>p’,最后替换后就成了个 $fileurl=’test.php’
问题已经清楚了,剩下的就是我们需要来构造一个$a_k,这里构造$a_k的值跟上一个SQL注入漏洞是一个套路,可以参考SQL注入漏洞的分析和构造过程。
在文件/phpcms/modules/wap/index.php中获取cookie的值;
在文件/phpcms/modules/attachment/attachments.php中,利用swfupload_json函数获取att_json的值;
这里att_json的值就是我们要的$a_k变量的构造内容。
注意这里一共通过了三次safe_replace函数,swfupload_json一次,init一次,download一次,所以我们在构造下载文件内容是需要绕过这个swfupload_json函数的三次过滤。
重点关注$fileurl = trim($s).trim($fileurl);这个以后的处理。
我们构造:
$s= ./phpcms/modules/content/down.ph $f= p%3%25252%2*70C(经过三次过滤后就成了个p>)
最后进入下载的文件文件就是./phpcms/modules/content/down.php
漏洞利用
访问:http://10.65.20.198/phpcms_v9.6.1_UTF8//index.php?m=wap&c=index&a=init&siteid=1
获取到这里的cookie:
KhLUs_siteid=923aWILP69vS49T0lonOkl-ZEWFgBRxEdmRHCEUx
然后将设置第二步的cookie:
KhLUs_userid=923aWILP69vS49T0lonOkl-ZEWFgBRxEdmRHCEUx
带上这个cookie访问:
上面标红的那一段为我们构造的payload,这里已下载./phpcms/modules/content/down.php为例子。
此时得到cookie:
KhLUs_att_json=61e9eXUqfQxngqteoYM_CiVo0b51zzeCuE5_VHIyoP3YykqDHLFO6HPa55Ir_qB1SMFU-P6X_ 6JXFspt3hyZrFMXgnV1Lo7J9PZmuTF54mglNf46wgQgyR2UfppuKTdmL_MzqcUtJ5i84JGYpjtefbuiHFoXdwCdIa 27T9CX53r7tnnmeDyQc-G4Fmnazj_9ZA
第三步我们将cookie,KhLUs_att_json的值付给a_k参数:
最后得到下载文件的url:
访问下载的url既可以下载./phpcms/modules/content/down.php文件。
漏洞利用脚本请见附件中的exp。
漏洞修复
这个漏洞主要是因为down类中download方法在进入file_down函数前有替换操作,这样在前面就可以将”<“或”>”带入到download中的f参数中绕过正则匹配。
官方发布了9.6.2版本,5月3日出了补丁,补丁地址:
http://download.phpcms.cn/v9/9.0/patch/utf8/patch_20170412_20170503_UTF8.zip
来看一下补丁的修复情况:
这里只是在进行了str_replace后再次正则匹配一下$fileurl参数的内容最后放入file_down函数中执行。
所以请升级到最新版。
如果您需要了解更多内容,可以
加入QQ群:570982169
直接询问:010-68438880
Nikki