DolphinPHP RCE漏洞分析
DolphinPHP RCE漏洞分析
参考:https://xz.aliyun.com/t/11118
漏洞点定位
跟修复的 Commit diff一下
可以看到对call_user_func
函数的调用增加了is_disable_func()
的判断,所以漏洞点就是application\common.php
的call_user_func
函数
漏洞分析
判断参数是否可控
从call_user_func
函数开始回溯,param[1]
是回调函数名称,log[$param[0]]
是传递给回调函数的参数。
**==$param[1]==**
:这个参数的值来自于解析日志规则时的 $match[1]
数组元素,而 $match[1]
是由正则表达式 /(\[\S+?\])/
匹配
$action_info['log']
得出的。这个正则表达式的含义是匹配方括号内的非空白字符,但不包括空格、制表符、换行符等。而$action_info['log']
是一个数据库查询操作的返回值。
**==$log[$param[0]]==**
:在上文中的代码中,$param[0]
的值是从日志规则中解析出来的。在正常情况下,$param[0]
代表的是一个特定的日志数据字段值
model('admin/action')->where('module', $module)->getByName($action)
的作用是根据特定的$module
和$action
,在数据库中查找对应的信息。找一下model,发现model('admin/action')
对应的数据表是admin_action
用phpstorm的插件连一下数据库,看一下表的结构是咋样的,如下图
那么我们现在就知道了,$action_info['log']
对应的就是指定的$module
和$action
对应的 log 值
那么log数据我们是否可控呢?可以在后台看到,action_log()
对应的功能是系统中的行为管理
且log值可控,没有任何校验
$param[1]
参数构造
我们现在已经可以确定call_user_func()
的回调函数名称$param[1]
是可控的,只需要将指定的 log 数据根据 “|” 分割后的第二个数据替换为恶意的函数名称即可,如[xxxxx|phpinfo]
$log[$param[0]]
参数构造
根据上述分析,$param[0]
也是可控的,只需要将指定的 log 数据根据 “|” 分割后的第一个数据替换即可。
那么我们看一下$log[]
有哪些字段值是可控的?答案是$model
和$details
是可控的
因此我们只需要令$param[0]
的值为$model
或$details
即可控制$log[$param[0]]
参数,也就是控制传递给回调函数的参数。
那么再进行回溯,看看哪里调用了action_log()
,且$model
或$details
可控
先查找action_log()
的用法
\app\admin\controller\Attachment::disable 处调用分析
查找用法发现了这个setStatus
方法,根据注释可以知道@param string $type 操作类型:enable,disable,delete
这个setStatus
方法通过call_user_func_array
调用了action_log
然后回溯一下setStatus
方法,发现\app\admin\controller\Attachment::disable
方法调用setStatus
并传参$type
为disable
,然后setStatus
方法从请求中获取要操作的记录ID(ids
),然后将这些ID转换为逗号分隔的字符串。接着,它调用了父类的 setStatus
方法,并传递了一些参数,包括$ids
也就是上文中提到我们需要可控的$details
参数,且该处对这个$ids
没有任何过滤和判断
即$ids
->$details
->$log[$param[0]]
可控
漏洞利用
上述分析中采用的皆为回溯调用的方式进行分析,现在从功能点开始入手进行完整的漏洞利用分析。
根据\app\admin\controller\Attachment::disable
方法的注释可知,此处对应的功能点为禁用附件
先打个断点调一下
功能点位于后台中系统的附件管理
根据代码需要禁用存在的附件,因此在个人信息处上传一个头像作为附件
可以看到附件处多出了一个附件
点击禁用并抓包
进入断点后一直跟进,成功进入到action_log
方法,并且看到$model
是 attachment_disable,$details
是我们可控的值
那么我们就在行为管理处修改 attachment_disable 的值
根据漏洞分析,将log值修改为如下
点击禁用附件
抓包修改ids
值,也就是action_log
方法中$log
数组的details
值
进入断点跟一下,先看看数据库操作
找一下对应的值,成功匹配到我们上面修改的规则[details|system]
继续跟进代码直到call_user_func
处
因为在行为管理处将attachment_disable
的日志规则修改为[details|system]
因此$param[0]='details'
$param[1]='system'
并且抓包修改了ids
为calc
,即$details
为calc
因此最终的执行语句为call_user_func("system","calc");
漏洞利用成功
官方漏洞修复分析
看了一下,官方修复方案就是加了黑名单检测,然后黑名单漏了不少php命令执行的函数(打过ctf的应该一眼能看出来了
一直到最新版也没有修复,直接交cnvd了(大概率重复了
更新一下,结果居然没有重复,还是水了一个cnvd