2019-10-15 11:29:4717375人阅读
2019年9月,禅道项目管理软件爆出全版本的RCE漏洞。于是便好奇漏洞的成因,在阅读作者的文章及自己复现分析后,发现漏洞其实算是一种越权调用,普通权限(用户组为1-10)的攻击者可通过module/api/control.php中getModel方法,越权调用module目录下所有的model模块和方法,从而实现SQL注入、任意文件读取、远程代码执行等攻击。
在分析漏洞之前,先需要了解禅道的路由模式。禅道有两种路由模式PATH_INFO(2)、GET方式,其中GET方式为常见的m=module&f=method形式传递模块和方法名,而PATH_INFO(2)则是通过路径和分隔符的方式传递模块和方法名。路由方式及分隔符定义在config/config.php中,下载的禅道11.6.1默认使用PATH_INFO路由方式。
接下来,从入口文件www/index.php开始分析禅道如何传参的,在index.php的66-68行,调用了三个方法parseRquest()、checkPriv()、loadModule()。
先跟进framework/base/router.class.php查看parseRquest方法,当路由方式为PATH_INFO或者PATH_INFO2的时候,会调用setRouteByPathInfo方法,将$this->URI用”-”分割,第一个参数设置为模块名,第二个参数设置为方法名,检查是否存在后传递到baseRouter类的变量中。
再跟进module/common/model.php checkPriv方法,主要是验证将要调用的模块和方法对当前用户是否有权限,除了isOpenMethod中定义的公开模块和方法之外,其他的方法都是需要登录的。
而本漏洞需要利用的模块和方法分别为api、getModel,可以zt_grouppriv表中查询调用该接口所需要的权限组为1-10,这意味着普通用户即可以调用该接口。
最后到load_Module方法,通过之前获取的moduleName包含对应的control类文件并实例化,随后调用setParamsByPathInfo方法从路径中获取方法对应的参数值,最后通过call_user_func_array方法调用对应control类中的对应方法并赋值。
存在漏洞接口为module/api/control.php的getModel方法,这是一个能够调用所有model类的超级方法,51行loadModel方法能否调用指定指定模块的model文件并返回model对象。配合52行的call_user_func_array函数便可以调用所有的model文件的所有方法。
原作者利用的是文件写入和文件包含结合执行任意代码,这里有一个更加简单的方式可以直接写入webshell。文件写入漏洞代码位于module/editor/model.php中的save方法,$filePath和$fileContent都可以控制。
要想写入php文件这里需要可以在路径中引入”.”,这里先看禅道会对PATH中传递的参数名和参数值限制规则config/filter.php,对参数值的正则为^[a-zA-Z0-9=_,`#+\^\/\.%\|\x7f-\xff]+$,这里其实是可以有”.”的。
但是为什么原作者放弃了直接写入webshell的方法呢,真实原因在framework/base/router.class.php的parsePathInfo方法,程序会先匹配路径中是否有”.”,如果有的话,将第一个点之前的部分作为需要解析的路径,之后的部分作为视图类型。这就解释了之前漏洞作者为什么没能直接写入webshell。
那么如何绕过呢,仔细分析程序发现在module/api/control.php的getModel方法中调用了parse_str对参数进行处理,而parse_str会对参数值做一次url解码!那么问题迎刃而解了,可以对”.”以及其他被限制的字符做两次url编码,即可以绕过对字符串中”.”的分割以及之后正则的匹配。直接写入webshell的请求如下:
由于路由的原因,必须覆盖www目录下的原有php文件才可以被直接解析,这里可以覆盖x.php。
http://foreversong.cn/archives/1410
本文由百度安全原创,转载请标注来源及原文链接