某道全版本rce漏洞分析

2019-09-11 约 68 字 预计阅读 1 分钟

声明:本文 【某道全版本rce漏洞分析】 由作者 ADog 于 2019-09-11 09:05:39 首发 先知社区 曾经 浏览数 1361 次

感谢 ADog 的辛苦付出!

1 厂商简介

禅道项目管理软件是一款国产的,基于LGPL协议,开源免费的项目管理软件,它集产品管理、项目管理、测试管理于一体,同时还包含了事务管理、组织管理等诸多功能,是中小型企业项目管理的首选,基于自主的PHP开发框架──ZenTaoPHP而成,第三方开发者或企业可非常方便的开发插件或者进行定制。
厂商官网:https://www.zentao.net/
而此次发现的漏洞正是ZenTaoPHP框架中的通用代码所造成的的,因此禅道几乎所有的项目都受此漏洞影响。

2 漏洞分析

漏洞代码位于module/control.php中的getModule函数,这里由于禅道路由的特性,会将所有符合pathinfo格式的参数给赋值到对应变量中,因此这里的moduleName,methodName,params参数都是用户可控的。

跟进这里的函数,其中param参数经过了explode函数,又经过了strpos和parse_str函数,简单来说这里其实就是参数赋值的作用,假如params对应位置的参数为users=admin,那么经过这里的处理后,params中就会传递users变量。
接着进入到loadModel函数,这里一开始踩了一个坑点,以为appName默认为空的话,在调用其module的时候会报错,从而进入不了42行中的代码,但是在动态调试后发现尽管appName为空,但是同样可以调用所有的module,也就意味着禅道module中的所有功能的model文件我们都能够直接越权调用,这主要是因为上图第50行中使用call_user_func_array来调用model文件中的函数。

这里以通过该漏洞获取管理员密码来走下动态审计的流程,把几个比较关键的点说一下。。
poc:http://127.0.0.1/zentaopms_11.6/www/api-getModel-user-getRealNameAndEmails-users=admin
在index.php的第67行会进入到用户模块的鉴权函数,禅道对各个模块都做了权限校验,很好的防止了用户的越权操作,因此这块比较关键,如果任意用户都能够调用api下的getModel函数,那么在后面的rce操作中就表示任意用户都能够做到。

这里首先获得moduleName和methodName,首先会判断这是否是一个开放的接口,但是这个接口并不是开放接口,所以进入到hasPriv的鉴权函数。

这里测试的用户是项目经理,可以看到rights信息包含用户可调用的control函数,可以看到api下的getmodel函数是true,所以也就表示当前用户是可以调用getmodel函数的。

鉴权完毕后开始调用函数,跟进这个loadModule函数

最终进入到call_user_func_array函数,这类的module为api,methodName为getmodel,注意看这里的param其实已经定义成了符合getmodel的参数名,在这段代码之前有一个初始化的过程,会从getmodel函数中取出传参变量名,然后将url中的参数给赋值到变量名里,那么这里继续走,使用call_user_func_array来调用getModel函数

这里传参就比较明显了,利用getModel函数作为跳板,继续调用user目录下的model.php文件中的getRealNameAndEmails函数,其中params为一个数组,那么继续跟进call_user_func_array函数

跟到这里,最终会去查询admin用户的信息,返回到前台,这里使用的角色是项目经理,所以是一种越权漏洞。

回到那个鉴权的问题,怎么去判断这个getModel函数是否是任意用户都能够调用的,后来发现在数据库里其实存放了对应的用户组,以及各个组可以使用的module和method。

这里可以看到正常的用户应该在前10个组里,虽然不能完全说是任意用户可控,但是感觉在实际场景中,能够登陆的用户一般都应该在前10个组里,所以这里说是任意用户可控感觉问题也不是很大。。

3 漏洞影响

下面是三个比较危害级别比较高的漏洞,这里简单介绍下审计流程。

3.1 sql注入

禅道的注入在9版本当时也出现过,原理是limit后的参数采用了直接拼接,但是现在这个版本的禅道对所有的sql语句都做了转义处理,并且get参数都有严格的限制,不能出现"()"等特殊符号,所以说要想要通过get去注入获得数据,会显得非常困难,另外要提到的一点就是禅道很多参数都会有base64的解码,这其实也是一个比较不错的突破口,但是这里发现了一个更明显的sql注入漏洞。
漏洞代码位于module/api/model.php文件的sql函数

这里其实是由很多限制的,比如说只能用select语句,并且其中可能还不能出现“()”这样的符号,因此这里只能采用最古老的的select语句去读数据库信息,虽然简单但是十分有效。
漏洞url:http://127.0.0.1/zentaopms_11.6/www/api-getModel-api-sql-sql=select+account,password+from+zt_user

这里简单说下禅道目前最新版所采用的pathinfo模式,首先通过传参确定进入的control文件为api,对应的method为getModel,接着开始对参数进行赋值,其中moduleName为api,methodName=sql,最后的param为sql=select+account,password+from+zt_user,那么调用了call_user_func_array函数后,会进入到api目录下的model文件,对应调用其中的sql函数,并通过赋值,将sql变量赋值为select+account,password+from+zt_user,最后执行query语句,造成数据库泄露。

3.2 文件读取

漏洞代码位于module/file/model.php中的parseCSV函数

这里通过上面的思路同样可以对fileName进行赋值,最终返回读取的文件数据
漏洞poc为:http://127.0.0.1/zentaopms_11.6/www/api-getModel-file-parseCSV-fileName=/etc/passwd

3.3 rce

一开始想要找的就是rce漏洞,所以通过寻找rce漏洞找到了禅道框架的漏洞,也是一个比较意外的收获吧。这里想要rce其实是文件写入+文件包含组合getshell的,所以只要我们都能够在model文件中找到这两类功能函数就能够达到我们的目的,另外这里可能有人会提出疑问,都能够写文件了,难道不能直接getshell嘛?这里写入的文件名没有经过base64解密,前面也说了禅道对于GET的参数其实是有多重限制的,像“.”也明显不在白名单规则里,所以最终放弃了这条路。
首先是文件写入漏洞,漏洞代码在module/editor/model.php中的save函数

这里对文件写入内容作了一定黑名单的限制,这个绕过比较简单就不多说了,懂的人都懂,另外会对filePath做可写限制,因此这里如果是linux服务器部署的话,推荐写在/tmp目录下,毕竟没有什么限制,而且物理路径比较可控,如果想要../来跳转目录写入,这个是会失败的。

文件包含这个点是在module/api/model.php的getMethod函数

这里传入filePath,最终经过了helper::import函数,这个函数跟进就会发现其实就是import函数,那么回到上面的代码,这里filePath就是我们写入的文件名,但是需要注意的是这里包含的是filePath的dirname,也就是说直接输入文件路径,最终包含的文件路径的上一级目录名,因此这里需要加上一层路径。

最终poc如下,需要给物理路径加上一层才能包含成功。

4 后记

上文都是在禅道开源版的11.6最新版本测试的,后来在开源版的9版本上测试了一把,发现禅道代码几乎没有改变,至少rce这几个接口的代码都是都没变的

虽然不是pathinfo模式,但是传参过程其实是一样的,这里也是文件写入+文件包含组合起来getshell。
后来又想看看禅道其他产品的代码怎样?这里又下了禅道专业版的最新版本发现同样的接口,所以也就会产生同样的漏洞。。最后推测禅道全版本全产品线应该都有相似的问题。。
如果想要修复这个漏洞,最简单的办法就是删除这个getModel接口。。

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now