PAYLAOD:
http://127.0.0.1/zentao116/api-getModel-api-sql-sql=select+account,password+from+zt_user
(需要用户权限)
第一眼看到这种传参方式,我心里是懵逼的,利用到的文件都看不出来,所以先研究一下他的URL是怎么写的。
PS:使用禅道前要将本地的apache服务和mysql服务关闭,否则会发生冲突
PS:由于环境限制,没办法搭建调试环境,所以文章中若是有错误内容还请师傅们务必斧正!!!∑(゚Д゚ノ)ノ
以URL:http://192.168.189.128/zentao/api-getModel-user-getRealNameAndEmails-users=admin
为例来说明参数传递过程
不管三七二十一,先上首页:/www/index.php
可以看到这里利用router::createApp
创建了一个新的应用,跟进该方法
应用名为:pms
,根路径为index.php路径的上级路径,应用类名为router。
这里最后返回了一个实例化的类,将app名字与根路径作为参数传入。由于这里创建了一个新对象,先去router类中看一下是否有__construct()
函数,没有找到就去他的父类baseRouter里找,果然在baseRouter中发现了__construct()函数
这里重要的是config文件,在358行调用到setConfigRoot设置了config文件的根目录:xxx/config/
接下来在363行调用到loadMainConfig来调用主配置文件
这里最后将主配置文件即/config/config.php做了include操作,跟进config.php文件
直接来看这一段
这段代码通过注释告诉我们,禅道的请求类型分为了三种:PATH_INFO、PATH_INFO2、GET
。
接下来回到index.php中,跳过运行app的过程,到达66行:$app->parseRequest();
跟进该函数:framework\base\router.class.php
可以发现,这里将PATH_INFO
和PATH_INFO2
模式归为一类,以-
方式传参,由于poc中出现了这种url传递的方式,所以继续跟进parsePathInfo
看一下。
parsePathInfo()
函数将URL以.
为分隔,前面的部分作为URI,.
后面的部分作为viewType。
回到parseRequets()
函数中,继续跟进setRouteByPathInfo()
函数
这里首先利用了$this->config->requestFix
分隔URI并整理为一个数组$item
,这里的$this->config->requestFix
即-
,接下来将数组中各个元素进行分配,$items[0]
为模块名,$item[1]
为方法名,在函数末尾设置控制器文件,函数结束。
接下来回到index.php
中,流程到$common->checkPriv();
,检测用户是否有权限访问应用。
再到$app->loadModule();
,加载模块,重要部分截图
这里会根据请求方式设置参数,由于是PATH_INFO
方法,继续跟进函数看看
这里用到该函数来取删掉前两个后的剩下的参数,赋值给params数组中。
再调用mergeParams函数将参数取出来合并并做调用
最后返回了$defaultParams
数组。
回到loadModule()
函数中,可以看到,函数的结尾调用了call_user_func_array()
函数,而且这里的函数也是我没见过的写法
/* 调用该方法 Call the method. */ call_user_func_array(array($module, $methodName), $this->params); return $module;
搜索了一下这种写法,发现然之协同oa也有相同的代码,这种写法相当于$module::$methodName($this->params)
,$methodName
必须是public类型才可以。
其实这里就是调用到了user
模块的getRealNameAndEmails
方法,传递的参数$params
即users=admin
跟进发现该方法就是查询用户账户的信息并返回,这样就差不多就搞明白禅道的传参方式了。
POC
http://127.0.0.1/zentao116/api-getModel-api-sql-sql=select+account,password+from+zt_user
根据前面的分析,先访问api模块的getModel方法
在函数50行的位置:
$result = call_user_func_array(array(&$module, $methodName), $params);
这样接下来就调用到api模块中的sql方法,跳转到该方法看一下
终于找到了执行SQL语句的位置,函数首先用trim
去除首位的空白字符,在99行处先将SQL语句显示在页面上,然后若是未查找到'select '
这样的字符串就直接查询SQL语句,看到这种代码,我瞬间感觉很是凌乱。
从这里可以得出一个教训,任何有关数据库的操作都必须经过很好的过滤,不能抱有任何侥幸心理,问题代码藏得再深都会被发现。
[渗透笔记]禅道(payload)
禅道11.6后台SQL注入漏洞复现分析(URL格式分析)