这是六月份的一个漏洞,当时漏洞作者直接在自己的blog公布细节了,但是对于初学者来说可能理解起来还是有点吃力,所以我对这个漏洞进行了跟踪复现,希望各位能有所收获。
首先我们直接看作者的payload
|
|
我们直接输入payload从Index.php开始跟踪。
跟进到init.php。
可以看到通过判断uri是否存在来判断是否进行路由跳转,如果是index.php或?开头则不跳转。
(trim和strpos都是常用的php函数,三元式也非常常见,不懂的朋友们可以自行翻看php手册,如果是mac用户可以安装一个dash,配上小帽子查阅会比较方便。)我们继续往下看。
这里直接跳到了流程处理文件。CI(CodeIgniter)是一个开源的php的web开发框架。所以你们会看到很明显的finecms自己的代码注释是中文,而CI部分的代码注释是英文。我们跟进去看。
CI是一个api类的实例,api类在/finecms/dayrui/controllers/Api.php
中。call_user_func_array
是php内置的一个调用用户函数的函数。传入回调函数和参数,其中参数为数组形式进行调用。如果要调用类的方法,则需要传入数组。如:
|
|
然后我们跟进api中的data2方法中。
auth的值会跟md5(SYS_KEY)进行比对,只有相同才能进行下一步。然后我们搜索SYS_KEY。
SYS_KEY是定义在/config/system.php
中的常量,换言之,对应的auth也是固定的。那压根就没有什么验证可言。这一步绕过了,然后往下看。
首先从REQUEST获取file参数。然后将空格转换为+号。判断文件夹是否存在,不存在则创建。然后重点来了,用正则提取file参数,(\w+)提取了MIME中的subtype。然而这里对subtype却没有进行任何过滤,所以当我们构造data:image/php;base64,xxxxx这样的参数时,会直接生成一个0x0.php
出来。最后,对后面的base64进行解码,写入这个生成的0x0.php
当中。这是将一句话或者马进行base64编码即可直接上传。
我们按照作者的payload测试一下,成功执行后访问对应的文件名。
成功显示phpinfo。
显然,开发者对file_put_contents过滤有问题。按照这个思路,大家可以搜索这个cms当中的file_put_contents函数,然后逆向跟踪。
另外一个思路,就是这里的SYS_KEY使用常量太蠢了,验证形同虚设,大家也可以根据这个去挖掘漏洞。