1,本次审计中出现bluecms内置复杂函数以及常用php函数统计归纳
2,bluecms简介与审计思路
3,user.php页面通过from参数请求遍历网站目录漏洞
4,user.php页面隐藏块from反射型XSS漏洞
5,ad_js页面SQL注入漏洞
6,用户资料编辑处的文件上传漏洞结合支付界面的包含漏洞挂马
bluecms部分内置函数:
template_assign($val1='', $val2='') val2的值赋给val1键,若数组单元数目不一样则报错; assign($tpl_var, $value = null) 将值$value分配给模板变量$tpl_va(没有传值就是null) showmsg($msg,$gourl='goback', $is_write = false) 弹出提示(或者可以通过$gourl跳转url) deep_addslashes($str) 将数组内的每一个字符深度过滤,使用php内置addslashes()方法 getone($sql, $type=MYSQL_ASSOC) 输入sql语句,输出查询结果的数组
PHP审计常见函数:
empty — 确定变量是否为空 trim — 去除字符串首尾处的空白字符(或者其他字符) * " " (ASCII 32 (0x20)),普通空格符。 * "\t" (ASCII 9 (0x09)),制表符。 * "\n" (ASCII 10 (0x0A)),换行符。 * "\r" (ASCII 13 (0x0D)),回车符。 * "\0" (ASCII 0 (0x00)),空字节符。 * "\x0B" (ASCII 11 (0x0B)),垂直制表符。 intval — 获取变量的整数值 返回变量 var 的 integer(Z*) 数值 str_replace — 子字符串替换 str_replace ( $search , $replace , $subject ) 该函数返回一个字符串或者数组。该字符串或数组是将 subject 中全部的 search 都被 replace 替换之后的结果。 time — 返回当前的 Unix 时间戳 $ _REQUEST — HTTP请求变量(接受POST和GET方法数据) 关联数组,默认情况下包含 $ _GET, $ _POST和 $ _COOKIE的内容。 addslashes — 使用反斜线引用字符串 这些字符是单引号(‘)、双引号(“)、反斜线(\)与 NUL(NULL 字符)。 is_array — 检测变量是否是数组 foreach — 语法结构提供了遍历数组的简单方式 array — 新建一个数组 count — 计算数组中的单元数目,或对象中的属性个数 ->是对象执行方法或取得属性用的。 =>是数组里键和值对应用的。 require_once 语句和 require、include 几乎完全一样 include 语句包含并运行指定文件。 magic_quotes_gpc boolean Warning 本特性已自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除。 为 GPC (Get/Post/Cookie) 操作设置 magic_quotes 状态。 当 magic_quotes 为 on,所有的 ' (单引号)、" (双引号)、\(反斜杠)和 NUL's 被一个反斜杠自动转义。 如果 magic_quotes_gpc 为关闭时返回 0,否则返回 1。在 PHP 5.4.O get_magic_quotes_gpc ( void ) : bool 起将始终返回 FALSE。 mysql_fetch_array — 从结果集中取得一行作为关联数组,或数字数组,或二者兼有 call_user_func — 把第一个参数作为回调函数调用 strpos — 查找字符串首次出现的位置 $_FILES -- $HTTP_POST_FILES [已弃用] — HTTP 文件上传变量 in_array — 检查数组中是否存在某个值 mkdir — 新建目录 getenv — 获取一个环境变量的值 include_once 语句在脚本执行期间包含并运行指定文件。此行为和 include 语句类似,唯一区别是如果该文件中已经被包含过,则不会再次包含。如同此语句名字暗示的那样,只会包含一次。
最近在拜读伊毅前辈的《代码审计——企业及web代码安全架构》这本书,很牛逼;书里面提到的三种最有效最常见的代码审计思路分别是以下三种:
- 检查敏感函数参数并进行变量回溯,判断其是否可控并且无严格过滤(逆向追踪)
- 寻找文件从外部接收的参数,跟踪该变量的传递过程,检查是否含有高危函数或逻辑漏洞(正向追踪)
- 通过外部可视功能点用以往经验进行针对性的功能代码块审计(老油条)
因为这是我第一次系统性的审计某个开源项目的代码,通过网上查阅资料,阅读前人所总结的经验,已经分享出来的该项目已爆出的漏洞,再自己后续的逐行代码的审计,分析;所以这篇博客只能说是一篇学习总结博客,并不能划分为开源项目代码审计的结果(要是以后工作上真的审计出来某项目的0day,那也不可能在博客上发表 = =\\ )
我这边总共总结分析了四个漏洞:
user.php页面通过from的$REQUEST请求遍历网站目录,访问旁站或浏览器打开文件
user.php页面隐藏块from反射型XSS
ad_js内SQL注入
用户资料编辑处的文件上传木马内容的图片,结合支付界面的包含漏洞,可以在根下生成木马挂webshell
其中第一和第二个是使用正向追踪的方法查出来的,第三个SQL注入也是正向追踪,最后一个文件上传漏洞是经验获得,文件包含漏洞是结合seay源代码审计工具逆向追踪查出来的,最后两个漏洞结合利用获得了webshell
开始审计整个CMS系统中功能最多,代码量最大的文件:user.php
可以看到这儿有两个主参数:$act $from;我们先跟踪一下$act:
这两行代码就是把act的值给固定住,使其变为不可控变量,因为它的默认值就是default。
接下来看$from:没有过滤,且没有固定变量
这个act=do_login就是cms的用户登录界面,这里的from被base64解码之后进行调用,们这里需要注意,继续看这个do_login代码块:发现这个代码块的最后末尾位置出现了showmag()函数吧from变量进行调用,看文字好像是页面跳转?跟踪函数showmsg():
showmag()函数代码:
在user.phg的112行这里只向内传入了两个参数,$from是第二个,也就是$gourl = $from,尾部if判断语句不再执行;
翻译:将值分配给模板变量* * @param array | string $ tpl_var模板变量名称* @param mixed $ value要分配的值;也就是$smarty内gourl键的键值是$from的值
继续追踪,穷追不舍,只为找到他的意义:
一个自动跳转页面,原来showmsg()函数的功能是传入一个url,然后实现网页自动跳转的功能
这段代码就解释得通了
因为想要触发do_login就必须先要登陆成功才能实现跳转的功能showmsg,所以先登录,其中from表单别忘了编码
既然跳到了我之前打的靶场上,我就会想到去试试是否存在XSS漏洞
发现from一直存在于user.php页面纸上,不受到act值变化的影响:
并且这里的from传入方法是$_REQUEST
构造了一个闭合,就出来了一个反射型XSS
舒服得很~(陕腔)
首先看ad_js.php代码:
就40行,有点舒服
其中,在第十九行位置进行与后台数据库的交互:跟踪getone()函数:
简单的说就是输入一端SQL语句,然后输出的是一端含有键值对的数组,这玩意儿在世界上最好的语言Python被叫做字典
重新看ad_js.php代码,最后面将输出的键值对进行了简单的字符替换:
我们来分析一下过滤的内容: " \r \n 双引号换行回车进行了过滤
这应该是规避闭合的安全措施:但是我发现了一个有意思的点:
没有闭合
对,你没有听错,这没有闭合
傻了啊兄弟,你这cms是用脚写的吧
有七列:最后的七十显示位:
漏洞验证成功。
在博客网页里面瞎转哟的时候发现,在修改个人资料(头像用户名等等)的地方,居然把头像的路径直接给你了:
太有意思了。我简直怀疑这个cms是不是web渗透靶场....
这里我想的是直接挂马,结果我用尽各种方法,都没办法上传php文件;以我的水平也许还差那么点Julia,反正我在这儿搞不进去php马....
但是这个cms的后台系统不会过滤和审查文件内容,也就是说我可以上传的文件只要后缀名是png(不能有截断什么的花里胡哨的玩意儿)就可以,于是我就上传了一个曲线救国木马.png:
是这样的,当初在写这个木马结合一个文件包含漏洞执行的时候怎么也出不来,有点自闭,最后网上一搜,发现这个php图片马的内容需要base64编码,我至今不知道这是为什么......
跳过去,先来找我们所需要的组合拳:文件包含漏洞,才能实现我们对于这个文件上传漏洞的组合攻击,挂webshell
这里用到了一款自动化代码审计的辅助工具:Seay
图标有点霸气,审
导入该cms项目,然后自动化审计,最后在user.php底下发现了一个疑似文件包含漏洞的地方:
位于user.php 750行的位置:
$act == 'pay' 处,我们先去Chrome上看看:
当我点击了在线支付以后:
因为这里管理员没有添加支付方式
加个题外话,这cms应该是2009年开发的,我看源码里面已经有对接支付宝付款的接口了,真牛逼啊,10年前,我10岁,在上4年级天天和小伙伴一块上天入地,爸妈用的都是三星Anycall的翻盖手机,我还在里面用10条一块钱的付费短信偷偷购买手机游戏,当时就记得那些像素游戏开头都会出现一个茶杯的标志,这里居然有cms完美支持支付宝平台了,厉害了!不愧是全中国第一梯队的PHP老兵!向我错过的那个时代致敬!
在家关久了,一个向往远方的内心有点自闭,话有点多,sorry
继续看代码:
这里居然对pay参数传入的数据没有做过滤(除了开头包含的文件里面的那几个传参过滤代码)
这里的pay应该传入的是一个目录地址,因为后面接的就是一个index.php页面,估计是管理员在后台设置好了支付方式以后,会自动在include/payment/下面创建一个支付方式的名字的目录,里面包含有一个index.php文件,也就是支付的跳转:
这里试试能不能直接在这儿进行文件的包含,我现在当前目录传入一个phpinfo.png图片,里面写一个phpinfo()函数:
看来需要做截断:
HEX编码后面加00不行
这也不行
于是我就开始想办法做一个曲线救国木马:
这里需要注意一个点,就是这个php程序执行之后会在当前目录下创建一个muma.php的木马文件,但是的这个当前的目录,是相对于 user.php这个文件来说的,因为这个include包含文件的点,是在user.php文件里面进行包含,执行,所以我们要挂马的话需要在bluecms的根目录下进行挂马操作:
注意别忘了关闭实时保护,不然简单的php木马就会被扫出来,很烦
直接上传头像图片
选择他的路径:
这里还要注意一下,就是包含的这个文件,最终需要写成如下所所示:
这是因为包含的文件原本是在include/payment底下,需要向后退两次,到达根目录;
包含成功;尝试挂马:
漏洞验证成功
有丶难受,但是写完之后感觉很通透
看了一天半的代码,写了大半天的博客,前前后后总共搞了三天的时间,感觉自己还是太菜了,效率确实不是很高,但实在是没有在电脑跟前玩手机,一直在写,一直在学
第一次代码审计,打算这个博客之后就去啃一周伊毅前辈的书:《代码审计——企业及web代码安全架构》
总之,先这样吧,马上要开学了,抓紧时间学技术,公司的事儿也不能放下,好好搞,机会难得,疫情搞得现在有太多的不确定性,以及太多的变数,不过人生就是这样吧,无限的可能,又或者大起大落;工作毕竟不是人生的全部,人类几千年的文明创造了文学,音乐,诗歌;祖国的雪山草原大海湖泊以及地球的第三极——西藏;生命本身毫无意义,都是出生以及死去,无一例外;唯一的不同就在于过程了;不要忘记当初为何出发,当初的理想就好了;
人生漫长转瞬即逝,有人见星辰,有人见尘埃