0x01 前言
phpcms是国内相对用的较多的cms之一。曾几何时,其安全性虽说不上好,但开发人员愿意正视安全漏洞,并有对安全漏洞有合理、正确、不粗暴的处理方式。 但这一年,我可以明显感到phpcms已经慢慢在放弃维护,就安全漏洞而言,处理手段越来越粗暴。随处可见的safe_replace函数(整个phpcms里,非数字型的输入有大量用这个函数进行处理):
虽说比部分cms直接拦截select、if要好很多,但这种方法也是粗暴不堪。大量搜索,搜不出有特殊字符的内容,就是这个函数在作怪。 我曾经跟一个朋友说过,当一个cms在惧怕安全问题,并开始用拦截、替换等粗暴方式处理漏洞的时候,就是它走向灭亡的开始。此类例子屡见不鲜,比如phpyun、cmseasy。 那么,这次这个安全漏洞是怎么出现的?
0x02 漏洞成因分析
我们可以下载源码,对比查看v9.5.9 -> v9.5.10和v9.5.10 -> v9.6.0的变化。 我们可以看到,在v9.5.10中,引入了一个新的类: db_mysqli.php。为什么phpcms要加这个类,其实从名字就可以看出, db_mysqli.php是对mysqli的一个封装。 在php5.5+以后,传统的mysql扩展就已经废弃了
1.jpg所以,phpcms也开始针对这个问题进行改进,这里引入mysqli这个封装类就是证明了这一点。不过,在v9.5.10中,默认使用的mysql封装类还是mysql:
2.jpg 根据配置文件在db_factory类中加载: 3.jpg 而在v9.6.0版本中,默认的mysql封装类换成了mysqli: 4.jpg这里,就是造成漏洞的关键点。我们对比一下这两个封装类的connect函数。
**/libs/classes/mysql.class.php:
**
expand source
**/libs/classes/db_mysqli.php
**
expand source
有何区别?mysql比db_mysqli里多了一段:
这段是干啥的?是设置character_set_client=binary。作用是防御宽字节注入的,在v9.6.0里居然忘记设置。(至于宽字节注入的原理与防御方法,见 https://www.leavesongs.com/PENETRATION/mutibyte-sql-inject.html ) 这就是新版phpcms里产生注入的原因。
0x03 寻找利用途径
这个漏洞点是存在于db_mysqli类中,这个类等于说是所有sql语句执行都会经过的类,所以我们只需找到一个满足以下条件的输入点:
字符型输入(不经过intval)
不经过safe_replace过滤
最好无需登录
在当前版本的phpcms中,因为大量位置经过了safe_replace过滤,所以这样的地方也不好找。不过去除第3个条件的话,位置还是比较多的。我简单找了两个位置,
一是 /modules/member/index.php:1473
可见这里直接将email传入get_one函数,一定存在注入。前面有个验证码的检测,实际上是可以绕过的,只要我们不传入code即可。 5.jpg这个注入无需登录,但需要网站配置了email。 另一个地方是需要登录的, /modules/attachment/attachments.php:155
这里从GET中获取data,放进delete函数里了。
6.jpg成功注入。
总结一下,这些注入,根本原因是宽字符注入,新版phpcms里由于代码更新换代导致遗失了之前的安全设置,导致出现安全漏洞。 因为是宽字符注入,所以注入是存在于GBK版本的phpcms里,UTF-8版本是不存在这个漏洞的。
网友评论