前言

我们今天来从零开始审计一款CMS:天目CMS
本文章由二农戏猪编辑

天目CMS 官网

MVC架构的了解

  • MVC架构一般包括三个部分:M是指业务模型,V是指用户界面,C则是控制器。具体情况大家可以百度查看。

  • 根据我们对于MVC的了解。我一般有两种审计模式:

直接审计控制器

也就C的内容,再追踪一些函数。全局搜索一下**filt__**,因为 filt 的英文意思为过滤,可以通过全局搜索这样式的函数来查看一下过滤规则。这种一般是比较快速审计。

但是这种情况一般建立在你可以清晰明白该款CMS的路由规则,适合老鸟,方便根据审计出来的漏洞的点去回溯验证

从index页面通读审计

这种审计方式是我认为像我这样的菜鸡比较合适的。也不容易忽略一些漏洞。该篇文章就是以这种方式审计的!

开始审计

准备

在审计开始时,我一般习惯于观察一下目录列表,从而可以对整个CMS有一个大概的了解:

1
2
3
4
5
6
7
app -----------------------------------  主程序目录
attachment ---------------------------- 附加目录
public -------------------------------- 公共程序
runtime ------------------------------- 一般为日志文件
temmoku ------------------------------- 一些插件,配置文件等
view ---------------------------------- 视图
index.php ----------------------------- 程序入口

index.php

我们可以看到的是index.php就是定义了一些常量,并且包含了 ‘temmoku’.DS.’run.php’ 这个文件。

image-20210210211353917

对于这些常量,我看到过一个表哥有一种方法,就是在index.php末尾去添加,将常量打印出来,保存到一个.txt中查找

记得点赞收藏哦!

1
2
3
foreach(get_defined_constants(true)['user'] as $k=>$v){
echo $k.'---'.$v."\r\n";
}

所以我们可以发现,DS就是\ ,它其实是包含了 temmoku\run.php 这个文件

run.php

然后我们进行跟进 ==>

image-20210210212409069

image-20210210212827281

好的,又是一堆常量和包含了 C:\phpstudy_pro\WWW\temmoku\temmoku\functions.php

C:\phpstudy_pro\WWW\temmoku\temmoku\app.php

这两个php文件,并且实例化app这个类中的run方法。

functions.php

跟入functions.php,发现里面定义的一脸的各种方法,先放着,等审计控制器中的某些地方具体调用时,再具体审计。

app.php

跟入app.php,开头看到namespaceuse这两个东西,不明白,好的,百度一下我们了解到: use 从同一个 namespace 中导入类、函数和常量。然后发现再run.php中调用了app这个类中的run方法,我们找一下。

image-20210210213836989

spl_autoload_register函数其实简单来讲就是自动实例化类。

Load_Class,就是将传进来的$class里面含有的\\转为/,判断存在就包含

image-20210215203905374

再跟进str_caps_look这个函数,前面我们传进来的$caps=1,将$class:xxx/xx,先分为xxx、xx转换为小写以后合并

image-20210215204247840

回到app.php,接下来就是调用setReporting()方法,简单看一下,不怎么重要,大概就是一些错误报告等级之类的东西。

default_config()方法,判断了caching.php这个文件是否存在,并且包含,看了一下就是去加载一个高速缓存的东西,这里我们注意一下,看看后面$setting['caching']会不会可控。

image-20210210214554200

冒险继续,这里定义了一个配置信息和一个路由信息,并且放入了Load_conf进行处理,我们跟进

image-20210210214911924

这里将末尾的conf 和 route单独拿了出来,并且将目录读取,将文件也读取,大概就是这么一个意思,也就是加载了conf配置和路由信息

image-20210210215340521

然后我们回到app.php中继续审计,在124行我们看到一个C方法,跟进,冲!!!!!!发现C方法其实就是加载了一些程序变量,对于这个东西,我还是采用看到的一篇文章中提到的方法,就是给C方法添加一个形式参数,然后去index.php末尾调用,然后将得到的程序变量保存在一个txt中,需要的时候去搜索。

后面就是去加载了一下版本信息

欸~~~,发现了个getRealIP这个方法,盲猜就是获取真实IP,啊哈哈哈哈哈

image-20210210222530227

嘿!好家伙,果然是这样的。我们发现,如果对CLIENT-IP进行伪造是不会成功的,但是是可以对X-FORWARDED-FOR参数进行伪造,这…..看不懂这个操作,这个就可以先记录,等完事儿看看会不会getRealIP给我们带来惊喜。审计就是这样,你永远不知道后面会发生什么。

image-20210210222740047

到这里基本default_config方法就看完了,后面就是对一些常量的定义了。

接着我们回到app.php中继续继续,20行实例化了一个route,我们回想起前面use temmoku\route,去文件夹里找一下,当看到对类进行实例化时候,我们一般是需要关注魔术方法,看到它先是对C:\phpstudy_pro\WWW\temmoku\app\module_route.php判断是否存在该文件,然后传入Load_file处理,就是在加载一些静态数组,并且定义了两个常量。

image-20210215205456471

接着是调用Route()这个方法,然后对这个方法里面往下看,前面以get方式获取到的PATH_INFO进行分割,遍历

image-20210215210707668

在接下来这个if分支,我们发现ROUTE这个数组默认为空,所以先放下不看

image-20210215211048571

这个就是定义了伪静态的方式

image-20210215211156798

如果给$_SERVER['PATH_INFO']传入了值,会以/分割,变成包含两个元素的数组,例如xxx/xx,变为xxx、xx,$test_module也就是传入的再第一个/以前的内容,然后就是将xxx转换为小写,之后判断是否安装,也就是$lock是否存在,存在则为已安装

image-20210215211409458

紧接着就是如果判断是否有 $test_module,如果没有,则定义MODULE为home

image-20210215212644510

接着我看到了熟悉的m、c、a,if条件语句里前面C(‘URL_RULES’)晓得是啥,后面'admin'!==MODULE,我们尝试一下用这种方式访问一下,看到是可以的,但是admin模块是不可以用这种方式访问。

image-20210215214837246

image-20210215215026742

139行就是如果没有定义模块,则默认为home模块,141-142行说的是admin模块是进行特殊的一个路由,就是Admin_Route()这个方法,这个一会儿再看。

image-20210215223322004

接着是加载插件和各个模块下的私有函数

image-20210215223659642

在159-174行,将$_SERVER['PATH_INFO']/分割,定义路由,例如home/index/index,指的就是home模块下,index控制器下,index方法。

image-20210215223757919

然后我们回过头来看Admin_Route(),也就是admin模块下的路由规则,同样也是将$_SERVER['PATH_INFO']/分割,然后去遍历,并且分别判断控制器是否为modular或plugin

image-20210215224629802

然后我紧接着发现了个大宝贝。这。。。。这就是过滤?

image-20210215225323616

我们追一下filtering这个函数,在functions.php这里面定义了过滤规则。将'id','aid','cid','uid','mid','cmid','iid','nid','cityid','proviceid','countyid','townid','upcid','state','reply_id','lid','iddb'都强制转换为int类型,然后放入htmlspecialchars进行实体化编码。

EMMMMM…….这里好像是杜绝了XSS的攻击,如果SQL注入的话,必须参数不能为上述,且为数字类型。又或者是同时查询两个参数,用\去绕过。不急。先继续看app.php

image-20210215225423683

self::log();这个函数发现是记录日志的个东西,先放着。

然后跟一下self::Load_Controller(),在app.php 63-75行,$home这个变量是否等为admin、user、install、home,如果是:$home为空,如果不是:$home=’\home’。

然后判断是否为插件。

判断控制器是否存在。如果存在,对这个controller进行实例化。

image-20210215230026372

跟进class controller,里面就是去验证了下会员状态

image-20210215231106913

返回上面跟入app.php 71行的函数,发现它是判断了一下是否存在方法

image-20210215232418607

==> 通过上面的审计,我们发现了有三种路由规则。

路由规则

  • 127.0.0.1/模块名/控制器/方法 所对应的文件路径为 ./app/模块名/controller/控制器.php所对应的方法则是传递过来的方法。

  • 127.0.0.1/?temmoku_dirs=模块名/控制器名/方法名所对应的文件路径为 ./app/模块名/controller/控制器.php

==> 所对应的方法则是传递过来的方法。

127.0.0.1/?m=模块名&c=控制器名&a=方法名 所对应的文件路径为 ./app/模块名/controller/控制器.php

所对应的方法则是传递过来的方法。该种规则不能用于admin模块

尝试一下,好的 ,没问题,就是这样的路由规则,接下来我们开始正式审计控制器。

image-20210215233138485

image-20210215233200839

image-20210215233218770

XRSec has the right to modify and interpret this article. If you want to reprint or disseminate this article, you must ensure the integrity of this article, including all contents such as copyright notice. Without the permission of the author, the content of this article shall not be modified or increased or decreased arbitrarily, and it shall not be used for commercial purposes in any way