摸鱼,审计几个CMS玩玩。
环境配置
Windows
路径:http://127.0.0.1/zentaopms/www/install.php,安装下载即可,数据库自动配置。
设置密码即可,注意这里不能设置弱密码,有弱口令检测。
这里踩了一个坑,这个地方下载的禅道CMS明显是修复过漏洞了,后来转用DockerHub的一个第三方Docker Image了。
Linux Powered by Docker
使用了第三方docker
sudo mkdir -p /data/zbox && docker run -d -p 8000:80 -p 2306:3306 -e ADMINER_USER="root" -e ADMINER_PASSWD="password" -e BIND_ADDRESS="false" -v /data/zbox/:/opt/zbox/ --add-host smtp.exmail.qq.com:163.177.90.125 --name zentao-server idoop/zentao:11.6
大致文件架构:
这个CMS本身并没有多少文件,简单易读,其中Index.php第39行可以传参:
查看配置信息
源码审计
搞清楚源码框架有点难,本着一个只会看框架配置文件和路由的小白,完全没摸着头脑,跟着雷神众测一篇文章进行了一波跟进分析。
首先在index.php的第30行创建了一个$app
。
跟进router的createApp函数,进入route.class.php,传入三个参数,分别是应用名称、应用根路径以及应用类名。
因为new了一个对象,要看它的构造方法,在同一文件的第348行:
在第358行设置了Config的根目录,在第363行加载了该配置文件,并进行了文件包含。
这里对框架路由进行了配置
/* 框架路由相关设置。Routing settings. */
$config->requestType = 'PATH_INFO'; // 请求类型:PATH_INFO|PATHINFO2|GET。 The request type: PATH_INFO|PATH_INFO2|GET.
$config->requestFix = '-'; // PATH_INFO和PATH_INFO2模式的分隔符。 The divider in the url when PATH_INFO|PATH_INFO2.
$config->moduleVar = 'm'; // 请求类型为GET:模块变量名。 requestType=GET: the module var name.
$config->methodVar = 'f'; // 请求类型为GET:模块变量名。 requestType=GET: the method var name.
$config->viewVar = 't'; // 请求类型为GET:视图变量名。 requestType=GET: the view var name.
$config->sessionVar = 'zentaosid'; // 请求类型为GET:session变量名。 requestType=GET: the session var name.
$config->views = ',html,json,mhtml,xhtml,'; // 支持的视图类型。 Supported view formats.
存在两种路由:一种是m、f、t来进行调用。另外一种是通过-来进行调用。
SQL注入
payload
http://127.0.0.1:8000/zentao/api-getModel-api-sql-sql=select+account,password+from+zt_user
查询成功。
这里的调用链比较复杂。根据刚才配置文件中的路由配置方式,定位到module/api/control.php文件中的getModel()方法。
向函数中传入三个值,其中$moduleName=api,$methodName=sql,$params=sql。
然后调用api中的sql方法并以sql=…..作为参数传递。
通过第110行代入SQL语句并执行。
任意文件读取
payload
http://127.0.0.1:8000/zentao/api-getModel-file-parseCSV-fileName=/etc/passwd
根据路由配置方式,定位到/module/api/control.php中的getModel()方法,传入三个参数分别为file、parseCSV、filename,其中filename为/etc/passwd。
同样,在代码的第59行调用file中的parseCSV方法并以filename=…..作为参数传递。
该方法在第一行就调用了文件读取。
$content = file_get_contents($filename);
成功读取文件。
这里需要注意一个点就是如果读取的文件是.txt、.php这种带后缀的,会被/framework/base/router.class.php中的parsePathInfo方法过滤掉。
任意文件写入RCE
payload
http://127.0.0.1:8000/zentao/api-getModel-editor-save-filePath=1111
POST: fileContent=<?php phpinfo(); ?>
相同的逻辑,根据路由配置方式,定位到/module/api/control.php中的getModel()方法,传入三个参数分别为editor、save、filepath,其中filepath=1111。
同理,在代码的第59行调用editor中的save方法并以filepath=…..作为参数传递。
先看一下这个方法
可以看到这里文件写入需要有权限的,并且会创建目录。
通过传入的$fileContent在第一行进行了调用。
$fileContent = $this->post->fileContent;
可以传入一句话木马直接RCE。
漏洞分析
可以看到这些漏洞的原理基本一致,都是在api中越权调用了getModel的方法,由于传入的参数全部可控,可以调用库函数中的全部方法,进而引发一系列的漏洞。同时由于该段代码普遍存在于各个版本的禅道CMS,影响较大,属于高危漏洞。