从0学代码审计——梦想CMS
0x01 前言
梦想CMS的最新版本好像是21年发布的,已经很久没更新了,毕竟也比较小众。于是就拿来锻炼一下自己的代码审计能力。
环境说明:
梦想CMS 1.4.1
php 5.4.45nts
mysql 6.5
有的游览器加载不了后台,可能是版本不兼容。
0x02 路由分析
梦想CMS是典型的MVC框架,弄清楚繁琐的路由是我们审计的第一步。
其实代码中都会有注释,看起来也不是那么吃力,根目录下有两个文件 index.php和 admin.php,分别为前台和后台的入口文件。
就拿前台来举例子

这里包含了两个文件。
config.inc.php 是一个配置文件,主要初始化一些前台相关的配置,注释很多,很人性化。
run.inc.php

根据前台还是后台获取不同的模板

加载一些控制器类,往下就进入到程序的入口

如果入口类型不是 extend ,就把它赋值为 Action。然后传递一个m参数,与 Action进行拼接,判断该类是否存在,如果存在就实例化,然后调用它的run方法。
这就解释了为什么前台和后台的控制器都是后缀为 Action 的格式了。

每个控制器都继承了 HomeAction 类,HomeAction类又继承了 Action 类,在 Action 类实现了run方法。

这里接收一个 a 参数,然后判断该控制器类是否存在 a 这个方法,如果存在就执行,不存在就执行 index 方法。这也就解释了为什么后台登录的url是要这么写了。

0x03 漏洞审计
1.后台任意文件删除
通过源代码审计系统发现一个 unlink删除函数

就定位到这个文件的这个函数中

如果 filename 可控,就可以实现任意文件删除了,前面拼接的路径完全可以用../来控制,已经没啥限制了。
接下来找调用了 del0ne 函数的地方。

Get 传递一个 filename 也没有做过多的处理,逻辑上是存在任意文件删除漏洞的。
在 file 目录下新建一个 1.txt,payload 如下
http://localhost:7080/admin.php?m=Backdb&a=delbackdb&filename=../1.txt |
可以发现 1.txt 已经被删除了。
2.后台sql注入
受到的启发就是这个

本以为这个会存在代码执行漏洞,就打算去看看

有个eval函数,如果$temdata[‘data’]可控,那么很容易能够代码执行,它是由 caijiDataOne 函数的返回值决定的,参数 cid 可控,感觉有戏,跟进到这个函数看一下。

拼接了一个 id=,继续跟进看

$temdata[‘data’] 取决于数据表中查询出来的值,完全不可控了,所以代码执行漏洞是不存在的。然后这里在进行sql语句拼接的时候没有做防护,此处应该会存在sql注入漏洞的。
执行如下payload
http://localhost:7080/admin.php?m=Acquisi&a=showCjData&id=1&lid=1&cid=1 union select 1,2,3,4,database(),6,7 |

漏洞是存在的。
3.后台任意文件写入
全局搜索敏感函数,比如 file_put_contents

定位到 file.class.php 文件

全局搜索哪些地方调用了 put 函数,验证漏洞是否存在就需要满足方法里的两个参数都是可控的。
在 TemplateAction.class. php 这个文件,首选的是要找控制器,因为能够直接通过url访问的。

都可控,漏洞存在,写一个phpinfo,payload如下
http://localhost:7080/admin.php?m=Template&a=editfile&dir=../ |
根目录会写入一个shell.php。

后台的漏洞审计就到此为止,其实存在后台的漏洞已经算不上真正意义上的漏洞了,非常难利用,后台管理员给的权限也极其的高。
4.前台sql注入
前台的漏洞算是真正的漏洞,危害也很大,当然也非常难发现。
在前台的 BookAction.class.php 控制器文件中

当 setbook 参数有值时,提交留言。首先调用 checkData 方法验证提交的数据。

验证不能频繁提交,,然后执行 filter_strs 方法剔除掉数据中的html和php标签,然后调用p函数又进行过滤,跟进看一下

遍历键值对,但是只是对键值做了过滤,没有对 键名做任何处理。
数据检查完后执行 add 方法与数据库进行交互。

insert 插入语句,field是键名,value是键值。可以对键名进行注入。
我们传入普通的数据,调试看完整的插入sql语句:

对照这条语句构造payload
POST /index.php?m=Book&a=index |
再看拼接好的sql语句

#号将后面的内容都注释掉了,键值对也一一对应,这样会执行 verson() 然后将执行结果写入name字段里。

已经写进去了。按理说应该可以将留言读取出来展示到页面上的。
还是在 index 方法

这里会走到这个if分支里面,然后将 where变量赋值为 ischeck=1
调用 count 方法查询 ischeck=1 的这一条数据,回看刚才的插入语句,我们已经将 ischeck 修改为1了,那么也会把mysql版本号的数据查出来,然后将查出来的数据填充到模板中,最终回显到html页面上。

果然危害大的漏洞比较难分析。
0x01 结语
本来想着看看自己能不能找到一个前台的漏洞,但是翻看了前台为数不多的控制器文件,并没有发现能够利用的地方,毕竟功能真的太少了,连个前台登录都没有。并且这个CMS在21年就断更了,已经没有再花更多时间去研究的必要了。拿来锻炼自己的审计思路还是挺不错的。