统计
  • 建站日期:2021-03-10
  • 文章总数:114 篇
  • 评论总数:0 条
  • 分类总数:12 个
  • 最后更新:4月29日
文章 代码审计

【通读审计】之DOYOCMS

自由子
首页 代码审计 正文

0x00 前言

首先大家看到我帖子的标题,我这里所谓的“通读审计”就是把整个代码审计过程一字不差的记录下来。因为审计过很多CMS,也看过很多代码审计文章,大多数都是把漏洞点提一下然后文章结束,对于不懂MVC的审计者来说,看其他人代码审计文章,很多细节问题搞不明白(因为我自己也是从那里过来的),所以读起来不是太舒畅,自己学习起来也有点吃力,尤其到MVC框架一块。然后这把就是给大家分享一下我个人的整个代码审计过程,以及如何发现漏洞,如何自己构造语句等等。这次审计的cms是DOYOCMS建站系统,因为我们学校使用的该系统,就随便拿一套过来记录吧。也是给自己做个记录,给大家分享个人经验。

(注意:由于是审计的整个过程,该文章比较啰嗦,大约2000多个字,大牛的话可以一略而过,像我这等小白就可以认真看一下,共同学习。)

0x01 MVC的了解

这里就不再废话了,直接就开始吧。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第1
张图片



Index.php第二行,上来直接require进来一个config.php,我们来看一下该文件到底做了哪些操作。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第2
张图片



OK,config.php文件定义了一些常量以及数据库信息。

Index.php第三行。

$doyoConfig['view']['config']['template_dir'] = APP_PATH.'/template/'.$doyoConfig['ext']['view_themes'];

如下图的变量值赋给

$doyoConfig['view']['config']['template_dir']



【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第3
张图片



Index.php的第四行的

require(DOYO_PATH."/sys.php");

把config.php的两个定义常量

define("APP_PATH",dirname(__FILE__));
define("DOYO_PATH",APP_PATH."/include");

的DOYO_PATH与sys.php拼接起来并且包含(包含include/sys.php)

我们看一下包含进来的sys.php文件进行了哪些操作


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第4
张图片



Sys.php的第四行包含进来一个Functions.php文件。从文件名上来看来猜测是包含来的一些方法吧。

打开看一下


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第5
张图片



好,确定包含方法。回到sys.php文件继续通读

Sys.php文件的第五行

$GLOBALS['G_DY'] = spConfigReady(require(DOYO_PATH."/inc.php"),$doyoConfig);

Require进来inc.php文件并且使用spConfigReady函数处理(之前提到的functions.php方法文件还记得吧)

跟进spConfigReady方法


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第6
张图片



可以看到第218行进行判断传入进来的$useconfig是否为数组,如果为数组进行遍历该数组,并且把传递过来的$useconfig保存到$preconfig内(合并数组)。

从他调用该方法中给形参1传递一个require进来的文件可以判断。该文件直接return一个数组。

打开包含进来的require(DOYO_PATH."/inc.php")文件来看一番


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第7
张图片



直接return一个数组

好,把inc.php文件return的数组与之前在index.php中定义过的$doyoConfig['view']['config']['template_dir']保存到全局变量$GLOBALS['G_DY']

回来继续读取sys.php


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第8
张图片



在functions文件中,跟进import方法。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第9
张图片



再来看一下传递进来的值


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第10
张图片



39-43行的

if( TRUE == @is_readable($sfilename) ){
        require($sfilename); 
        $GLOBALS['G_DY']['import_file'][md5($sfilename)] = TRUE; 
        return TRUE;
}

进行判断形参$sfilename是否可读,可读即包含。



OK,了解完import是用来读取文件之后,我们随着依次打开


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第11
张图片



这三个文件,看一下都有哪些操作。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第12
张图片



哈哈,三个文件都是定义的类文件。

从字面上来看

syController:Controller的表面意思为控制器

syModel:Model的表面意思为模型

syView:View的表面意思为视图

MVC…

再回来读sys.php文件的第29-36行


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第13
张图片



判断分支给$GLOBALS['G_DY']['url']["url_path_base"]进行赋值

再读取sys.php文件的第42-50行

看到!empty($_SERVER['PATH_INFO'],是用来实现伪静态化的操作的

下面的52-58行是作为重点。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第14
张图片



判断分支给$GLOBALS['G_DY']['url']["url_path_base"]进行赋值

再读取sys.php文件的第42-50行

看到!empty($_SERVER['PATH_INFO'],是用来实现伪静态化的操作的

下面的52-58行是作为重点。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第15
张图片



跟进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."类定义不存在,请检查。");
}

【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第16
张图片



0x02 PHP任意文件替换漏洞

紧接着上面继续往下分析

我们打开sysession文件看一下。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第17
张图片



自改了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’的写入规则。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第18
张图片



比如,这里有一个1.php。文件内容为123,当你file_put_contents(‘1.php’,’xxx’);的时候,1.php文件内容”123”会被替换为我们传入的”xxx”

再来看看程序自写的session存储机制居然没有对路径做任何过滤。

那么就比较有趣了。我们可以通过修改session的值。来进行替换任何文件。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第19
张图片



就可以成功把根目录下的 /include/inc.php 文件内容给替换掉。include/inc.php 文件内容为网站配置。该框架中有运行。再结合之前程序写入session文件内容所定义的<?php die();?>。可以导致网站无法正常访问。(被die暂停程序运行)。

验证漏洞结果:


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第20
张图片



0x03 继续观察MVC

我们再回到functions.php文件进行读取第11行

$handle_controller = syClass($__controller, null, $GLOBALS['G_DY']["controller_path"].'/'.$__controller.".php");

进行syClass函数处理。我们之前了解到syClass方法是用来处理类文件并包含的。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第21
张图片



传入的第三个参数亮了。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第22
张图片



根据我们传递的参数,则/source/$_GET[‘c’]是我们所包含的文件。我们在source文件夹下创建test.php进行验证一下


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第23
张图片



看来逻辑是没有问题的

接着我们继续往下看functions.php文件的第16行


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第24
张图片



这样来,我们整个的处理逻辑搞清楚开始挖掘漏洞

0x04 SSRF漏洞

当前我在functions.php这个文件。既来之,则安之。我通过危险自定义的一些方法来寻找漏洞

我从functions.php文件的第100-117行发现了


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第25
张图片



该函数传入的$url如果没有严谨的过滤,则会造成SSRF漏洞

全局搜索一下这个函数。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第26
张图片



看到大名鼎鼎的a_sys类文件($_REQUEST[‘c’])与调用该漏洞的方法($_REQUEST[‘a’])


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第27
张图片



可是问题来了,我们所包含类文件的路径是 /source,而不是/source/admin/xxx.php

那么我们如何引入呢?不慌。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第28
张图片



全局搜索一下哪里修改了$doyoConfig['view']['config']['template_dir']的值(该值影响包含路径)

在admin.php中重现了index.php的操作。只是略有一些不同


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第29
张图片



那么我们SSRF漏洞利用点也只能在后台了,有一定的局限性

登陆后台后

我们包含a_sys.php文件并实例化该类,然后调用template_cache方法


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第30
张图片



这里是传入的$y。我们再该文件内翻半天也不会翻到syArgs方法的。

原因很简单,继承了一个类。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第31
张图片



这里构造方法有了和template_cache方法相同的步骤

我们之前所看过的这个类的一个syArgs方法

可是在syController中也没有找到syArgs方法,那么我们就需要看一下__call魔术方法的处理了


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第32
张图片



第48行

return syClass($name)->input($args);

syClass我们之前了解到的功能就是进行包含syArgs这个类文件或实例化该类,随后调用
input方法,把我们construct的$this->a=$this->syArgs('a',1);中’a’,1以数组的形式传递给input方法


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第33
张图片



看一下get方法


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第34
张图片



调用了has方法,把字符串’a’传递进去了

跟进has方法


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第35
张图片



咦?多了一个成员属性$this->args

我们看一下构造方法是否初始化该属性



该类的构造方法


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第36
张图片



args成员属性是$_REQUEST进来的变量

如果我们传入的?a=template_cache,返回true

再回来看一下该分支结构


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第37
张图片



继续跟进filters方法


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第38
张图片



看到该方法是用来过滤传入数据内容的。在其中的 case 0,1,2,3,4,5,中,可以看到都对传入的数据进行过滤操作。可是在case 2中,漏洞出现了。这里涉及到array_walk_recursive函数利用问题。

看着arrays方法的代码块,好像过滤的还挺全的。不仔细想一想还真不知道。

array_walk_recursive函数并不会影响到数组本身。例如:


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第39
张图片



可以看到我们放入的 test=>’aaa,单引号并没转义。好了,现在了解到syArgs的第二个参数存在未过滤问题。

我们继续回到第102-105行的操作

再回到我们之前这一步


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第40
张图片



把我们传入的y进行实体化编码(htmlspecialchars)以及防注入(addslashes)操作,但是我们当前发现的漏洞输入SSRF类型的,所以对我们毫无影响~

好了,构造payload: admin.php?c=a_sys&a=template_cache&y=127.0.0.1:3306

验证漏洞结果:


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第41
张图片



0x05 SQL注入漏洞

那么我们知道syArgs(x,2)的第二个参数存在漏洞问题之后。我们全局搜索:,2)。来查找哪一地方使用了该函数。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第42
张图片



可以看到update关键词。这东西对我们非常敏感。审计突然就像喝了红牛一样。精神杠杠的。

PS:这里if验证跟进就不再说了。直接看update。写了2000字了。内心有点恶心。。


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第43
张图片



果然,是自己封装的update语句。

那么构造

Payload:?c=a_classtypes&a=alledit&orders[]=1' or updatexml(2,concat(0x7e,(version())),0) or'

验证漏洞结果:


【通读审计】之DOYOCMS
-纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
-第44
张图片

版权所有:纵横安全网-渗透测试-软件开发-前端开发-PHP全栈
文章标题:【通读审计】之DOYOCMS
除非注明,文章均为 纵横安全网-渗透测试-软件开发-前端开发-PHP全栈 原创,请勿用于任何商业用途,禁止转载

扫描二维码,在手机上阅读

版权说明
文章采用: 《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权。
版权声明:未标注转载均为本站原创,转载时请以链接形式注明文章出处。如有侵权、不妥之处,请联系站长删除。敬请谅解!

-- 展开阅读全文 --
挖掘犯罪链条中的URL跳转
« 上一篇
越南黑客通过Facebook Messenger部署基于Python的Stealer
下一篇 »
为了防止灌水评论,登录后即可评论!

HI ! 请登录
注册会员,享受下载全站资源特权。

最新评论

标签