【通读审计】之DOYOCMS
0x00 前言
首先大家看到我帖子的标题,我这里所谓的“通读审计”就是把整个代码审计过程一字不差的记录下来。因为审计过很多CMS,也看过很多代码审计文章,大多数都是把漏洞点提一下然后文章结束,对于不懂MVC的审计者来说,看其他人代码审计文章,很多细节问题搞不明白(因为我自己也是从那里过来的),所以读起来不是太舒畅,自己学习起来也有点吃力,尤其到MVC框架一块。然后这把就是给大家分享一下我个人的整个代码审计过程,以及如何发现漏洞,如何自己构造语句等等。这次审计的cms是DOYOCMS建站系统,因为我们学校使用的该系统,就随便拿一套过来记录吧。也是给自己做个记录,给大家分享个人经验。
(注意:由于是审计的整个过程,该文章比较啰嗦,大约2000多个字,大牛的话可以一略而过,像我这等小白就可以认真看一下,共同学习。)
0x01 MVC的了解
这里就不再废话了,直接就开始吧。
Index.php第二行,上来直接require进来一个config.php,我们来看一下该文件到底做了哪些操作。
OK,config.php文件定义了一些常量以及数据库信息。
Index.php第三行。
$doyoConfig['view']['config']['template_dir'] = APP_PATH.'/template/'.$doyoConfig['ext']['view_themes'];
$doyoConfig['view']['config']['template_dir']
Index.php的第四行的
require(DOYO_PATH."/sys.php");
define("APP_PATH",dirname(__FILE__));
define("DOYO_PATH",APP_PATH."/include");
我们看一下包含进来的sys.php文件进行了哪些操作
Sys.php的第四行包含进来一个Functions.php文件。从文件名上来看来猜测是包含来的一些方法吧。
打开看一下
好,确定包含方法。回到sys.php文件继续通读
Sys.php文件的第五行
$GLOBALS['G_DY'] = spConfigReady(require(DOYO_PATH."/inc.php"),$doyoConfig);
跟进spConfigReady方法
可以看到第218行进行判断传入进来的$useconfig是否为数组,如果为数组进行遍历该数组,并且把传递过来的$useconfig保存到$preconfig内(合并数组)。
从他调用该方法中给形参1传递一个require进来的文件可以判断。该文件直接return一个数组。
打开包含进来的require(DOYO_PATH."/inc.php")文件来看一番
直接return一个数组
好,把inc.php文件return的数组与之前在index.php中定义过的$doyoConfig['view']['config']['template_dir']保存到全局变量$GLOBALS['G_DY']
回来继续读取sys.php
在functions文件中,跟进import方法。
再来看一下传递进来的值
39-43行的
if( TRUE == @is_readable($sfilename) ){
require($sfilename);
$GLOBALS['G_DY']['import_file'][md5($sfilename)] = TRUE;
return TRUE;
}
OK,了解完import是用来读取文件之后,我们随着依次打开
这三个文件,看一下都有哪些操作。
哈哈,三个文件都是定义的类文件。
从字面上来看
syController:Controller的表面意思为控制器
syModel:Model的表面意思为模型
syView:View的表面意思为视图
MVC…
再回来读sys.php文件的第29-36行
判断分支给$GLOBALS['G_DY']['url']["url_path_base"]进行赋值
再读取sys.php文件的第42-50行
看到!empty($_SERVER['PATH_INFO'],是用来实现伪静态化的操作的
下面的52-58行是作为重点。
判断分支给$GLOBALS['G_DY']['url']["url_path_base"]进行赋值
再读取sys.php文件的第42-50行
看到!empty($_SERVER['PATH_INFO'],是用来实现伪静态化的操作的
下面的52-58行是作为重点。
跟进syClass与spLaunch方法
function syClass($class_name, $args = null, $sdir = null, $force_inst = FALSE){
if(preg_match("/^[a-zA-Z0-9_\-]*$/",$class_name)==0)syError("类定义不存在,请检查。");
if(TRUE != $force_inst)if(isset($GLOBALS['G_DY']["inst_class"][$class_name]))return $GLOBALS['G_DY']["inst_class"][$class_name];
if(null != $sdir && !import($sdir) && !import($sdir.'/'.$class_name.'.php'))return FALSE;
$has_define = FALSE;
if(class_exists($class_name, false) || interface_exists($class_name, false)){
$has_define = TRUE;
}else{
if( TRUE == import($class_name.'.php')){
$has_define = TRUE;
}
}
if(FALSE != $has_define){
$argString = '';$comma = '';
if(null != $args)for ($i = 0; $i < count($args); $i ++) { $argString .= $comma . "\$args[$i]"; $comma = ', ';}
eval("\$GLOBALS['G_DY']['inst_class'][\$class_name]= new \$class_name($argString);");
return $GLOBALS['G_DY']["inst_class"][$class_name];
}
syError($class_name."类定义不存在,请检查。");
}
0x02 PHP任意文件替换漏洞
紧接着上面继续往下分析
我们打开sysession文件看一下。
自改了session存储机制。注意看write方法。写入session操作。
看到在file_put_contents写入前拼接了” <?php die();?>”关键字。首先我们想到php://filter进行绕过。但是我们可以看到前面拼接了一个$filedir。$filedir变量是路径信息。不可控。则php://filter无法绕过。
file_put_contents在windows下我们可以进行写入冒号文件流的格式。例如:xxx.php:.php。可以逃逸<?php exit;?>。但是生成后的文件却是空的。再进行xxx.php<<<写入文件数据,思路是这样的,但是。我们还可以看到在拼接$name的同时。后面连接了一个’.php’。那么我们提交的数据就变成了xxx.php<<<.php。显然。打乱了文件流规则。也无法利用!
我们没有任何机会来通过session文件来getshell
但是从另一个角度讲,file_put_contents函数是由fopen函数与fwrite函数封装起来的。使用了’w’的写入规则。
比如,这里有一个1.php。文件内容为123,当你file_put_contents(‘1.php’,’xxx’);的时候,1.php文件内容”123”会被替换为我们传入的”xxx”
再来看看程序自写的session存储机制居然没有对路径做任何过滤。
那么就比较有趣了。我们可以通过修改session的值。来进行替换任何文件。
就可以成功把根目录下的 /include/inc.php 文件内容给替换掉。include/inc.php 文件内容为网站配置。该框架中有运行。再结合之前程序写入session文件内容所定义的<?php die();?>。可以导致网站无法正常访问。(被die暂停程序运行)。
验证漏洞结果:
0x03 继续观察MVC
我们再回到functions.php文件进行读取第11行
$handle_controller = syClass($__controller, null, $GLOBALS['G_DY']["controller_path"].'/'.$__controller.".php");
传入的第三个参数亮了。
根据我们传递的参数,则/source/$_GET[‘c’]是我们所包含的文件。我们在source文件夹下创建test.php进行验证一下
看来逻辑是没有问题的
接着我们继续往下看functions.php文件的第16行
这样来,我们整个的处理逻辑搞清楚开始挖掘漏洞
0x04 SSRF漏洞
当前我在functions.php这个文件。既来之,则安之。我通过危险自定义的一些方法来寻找漏洞
我从functions.php文件的第100-117行发现了
该函数传入的$url如果没有严谨的过滤,则会造成SSRF漏洞
全局搜索一下这个函数。
看到大名鼎鼎的a_sys类文件($_REQUEST[‘c’])与调用该漏洞的方法($_REQUEST[‘a’])
可是问题来了,我们所包含类文件的路径是 /source,而不是/source/admin/xxx.php
那么我们如何引入呢?不慌。
全局搜索一下哪里修改了$doyoConfig['view']['config']['template_dir']的值(该值影响包含路径)
在admin.php中重现了index.php的操作。只是略有一些不同
那么我们SSRF漏洞利用点也只能在后台了,有一定的局限性
登陆后台后
我们包含a_sys.php文件并实例化该类,然后调用template_cache方法
这里是传入的$y。我们再该文件内翻半天也不会翻到syArgs方法的。
原因很简单,继承了一个类。
这里构造方法有了和template_cache方法相同的步骤
我们之前所看过的这个类的一个syArgs方法
可是在syController中也没有找到syArgs方法,那么我们就需要看一下__call魔术方法的处理了
第48行
return syClass($name)->__input($args);
syClass我们之前了解到的功能就是进行包含syArgs这个类文件或实例化该类,随后调用__input方法,把我们__construct的$this->a=$this->syArgs('a',1);中’a’,1以数组的形式传递给__input方法
看一下get方法
调用了has方法,把字符串’a’传递进去了
跟进has方法
咦?多了一个成员属性$this->args
我们看一下构造方法是否初始化该属性
该类的构造方法
args成员属性是$_REQUEST进来的变量
如果我们传入的?a=template_cache,返回true
再回来看一下该分支结构
继续跟进filters方法
看到该方法是用来过滤传入数据内容的。在其中的 case 0,1,2,3,4,5,中,可以看到都对传入的数据进行过滤操作。可是在case 2中,漏洞出现了。这里涉及到array_walk_recursive函数利用问题。
看着arrays方法的代码块,好像过滤的还挺全的。不仔细想一想还真不知道。
array_walk_recursive函数并不会影响到数组本身。例如:
可以看到我们放入的 test=>’aaa,单引号并没转义。好了,现在了解到syArgs的第二个参数存在未过滤问题。
我们继续回到第102-105行的操作
再回到我们之前这一步
把我们传入的y进行实体化编码(htmlspecialchars)以及防注入(addslashes)操作,但是我们当前发现的漏洞输入SSRF类型的,所以对我们毫无影响~
好了,构造payload: admin.php?c=a_sys&a=template_cache&y=127.0.0.1:3306
验证漏洞结果:
0x05 SQL注入漏洞
那么我们知道syArgs(x,2)的第二个参数存在漏洞问题之后。我们全局搜索:,2)。来查找哪一地方使用了该函数。
可以看到update关键词。这东西对我们非常敏感。审计突然就像喝了红牛一样。精神杠杠的。
PS:这里if验证跟进就不再说了。直接看update。写了2000字了。内心有点恶心。。
果然,是自己封装的update语句。
那么构造
Payload:?c=a_classtypes&a=alledit&orders[]=1' or updatexml(2,concat(0x7e,(version())),0) or'
验证漏洞结果:
自评TCV:4(4月份开头,4月1号,脸大,我想要4个 )
评论31次
多谢楼主分享,学xi了
还不错,适合新手!
MVC架构代码跟踪起来比较复杂,看起了比较复杂,thinkphp就是这样的架构.Laravel感觉也是这样的架构
楼主辛苦了
审计的时候,看路由,很费劲,跟着跟着就跑偏了
这么详细的,涨知识了
MVC架构也就是国内这么喜欢用罢了,为社么推崇MVC呀?难道开发代码的时候已经想着程序员离职怎么办了吗?
这是现在比较流行的开发模式吧,tp框架等等框架都是用的MVC开发模式。
MVC架构也就是国内这么喜欢用罢了,为社么推崇MVC呀?难道开发代码的时候已经想着程序员离职怎么办了吗?
感谢,对我们这种刚刚入门审计的小白的确很有效果,之前拿到源码都不知道如何下手。搞了一天一无所获。
跟着走了一遍,脑袋好乱呀
很详细啊,能跟着审一波,新手友好,学xi一下
文章写的确实不错,这个程序员是临时聘请的吧。一个index.php这么多洞
留个名记录下,晚上用电脑仔细学xi学xi,mvc模式的的确头疼
不错非常详细!感谢楼主分享。
收藏 晚上回来看 大致看了一下真的详细 对我这种菜狗真的友好 舒服
受教了,收藏
这个审计 真的是在手把手的教啊。 审计需要细心,佩服佩服
好文,学xi了。
老哥拿Notepad 调试也是6,收藏一下
notepad是个人xi惯,因为可以搜索函数嘛
我能求一求源码吗
源码可以在doyocms官网可以下载到的。