addslashes防注入的绕过案例(AFSRC获奖白帽子情痴)

时间:2022-05-06
本文章向大家介绍addslashes防注入的绕过案例(AFSRC获奖白帽子情痴),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

代码审计中遇到的一些绕过addslashes的案例

From ChaMd5安全团队核心成员 无敌情痴

MMMMM叫我写一篇文章发到公众号,然而我是ChaMd5安全团队第一弱的大菜逼,于是就写篇基础的审计文章,在实际情况中,会出现各种各样的绕过防注入的手法,我这里只是列举了我在实际审计中遇到的比较常见的绕过方法。

前段时间审计过不少PHP开源系统,而很多PHP开源系统针对sql注入都喜欢用addslashes来防止注入,也就是把’ “ %00 这些符号转义在前面加个。

根据实际的情况,也有各种绕过addslashes的方法,今天写写几个代码审计中绕过addslashes的实例。

第一种情况:虽然使用了addslashes转义,但是缺没有加引号,直接无视过滤。

$money=$_GET['money'];//相当于交易中的支付金额

mysql_query("update `go_member`set money=money+$money where uid='$uid'"); //会员表加款

这套系统是有对$_GET,$_POST,$_COOKIE这些可控数据做addslashes的,但是这里的$money便利在带入sql语句的缺没有加引号,本来addslashes防止sql注入的原理就是转义’ “ %00这些有特殊含义的符号,防止它逃出引号,但是这里没有加引号,所以可以直接构造任意sql语句了,无视过滤

成功得到数据

第二种情况:宽字节注入

具体原理可以参考一下P神的文章

http://www.freebuf.com/articles/web/31537.html

简单的说有两种情况可能会造成宽字节注入,这样设置数据库的字符集为gbk

mysql_query(“SET NAMES ‘gbk'”);
<?php
if(is_null($_REQUEST[‘username’]) || is_null($_REQUEST[‘password’]))
{
        die();
}
$link=mysql_connect(“localhost”,”root”,”root”);
mysql_query(“SET NAMES ‘gbk'”);
mysql_select_db(“test”,$link);
$username=$_REQUEST[‘username’];
$password=md5($_REQUEST[‘password’]);
$sql=”select count(*) as num from admin where name='”.addslashes($username).”‘ and pass='”.$password.”‘”;
$query=mysql_query($sql);
$res=mysql_fetch_array($query);
$count=$res[‘num’];
if($count==1)
{
        echo “login success”;
}
else
{
        echo “login failed”;
}
?>

比如说这段代码就存在宽字节注入,或者是在使用iconv,mb_convert_encoding转换字符编码函数导致宽字节注入,来一个自己审计中发现的宽字节注入案例

elseif($act == 'get_company')
{
$type=trim($_GET['type']);
$key=trim($_GET['key']);
if (strcasecmp(QISHI_DBCHARSET,"utf8")!=0)
{
$key=iconv("utf-8",QISHI_DBCHARSET,$key);
} 
if ($type=="getuname")
{
$sql = "select * from ".table('members')." AS m  LEFT JOIN  ".table('company_profile')." AS c ON  m.uid=c.uid where m.username like '{$key}%' AND m.utype=1 LIMIT 20";
}
elseif ($type=="getcomname")
{
$sql = "select * from ".table('company_profile')." where companyname like '%{$key}%'  LIMIT 30";
}
else
{
exit();
}
$result = $db->query($sql);
while($row = $db->fetch_array($result))
{
if (empty($row['companyname']))
{
continue;
}
$row['addtime']=date("Y-m-d",$row['addtime']);
$row['company_url']=url_rewrite('QS_companyshow',array('id'=>$row['id']));
$info[]=$row['id']."%%%".$row['companyname']."%%%".$row['company_url']."%%%".$row['addtime'];
}
if (!empty($info))
{
exit(implode('@@@',$info));
}
}

同样这套系统也是有做addslashes的,但是

$key=iconv("utf-8",QISHI_DBCHARSET,$key);

$key这个可控变量在addslashes之后用iconv函数转换编码,造成宽字节注入

第三种情况是可控做了addslashes之后,可控变量进入了各种函数比如,base64_decode,urldecode,json_encode,stripslashes,举个案例以前在审计某套系统的时候,发现那套系统有这样一个url解码函数,于是搜索了一下,发现这套系统很多地方都调用了这个函数,所有调用这个函数对可控变量进行处理之后带入sql语句的地方都存在sql注入

function unescape($str){
        $code = PHP_OS == 'Linux' ? 'UCS-2BE' : 'UCS-2';
        $str = rawurldecode($str);
        preg_match_all("/%u.{4}|&#x.{4};|&#d+;|.+/U", $str, $r);
        $ar = $r[0];
        foreach($ar as $k => $v){
                if(substr($v, 0, 2) == "%u"){
                        if(function_exists('mb_convert_encoding')){
                                $ar[$k] = mb_convert_encoding(pack("H4", substr($v, -4)), strtoupper(IN_CHARSET), "UCS-2");
                        }else{
                                $ar[$k] = iconv($code, strtoupper(IN_CHARSET).'//IGNORE', pack("H4", substr($v, -4)));
                        }
                }elseif(substr($v, 0, 3) == "&#x"){
                        if(function_exists('mb_convert_encoding')){
                                $ar[$k] = mb_convert_encoding(pack("H4", substr($v, 3, -1)), strtoupper(IN_CHARSET), "UCS-2");
                        }else{
                                $ar[$k] = iconv($code, strtoupper(IN_CHARSET).'//IGNORE', pack("H4", substr($v, 3, -1)));
                        }
                }elseif(substr($v, 0, 2) == "&#"){
                        if(function_exists('mb_convert_encoding')){
                                $ar[$k] = mb_convert_encoding(pack("H4", substr($v, 2, -1)), strtoupper(IN_CHARSET), "UCS-2");
                        }else{
                                $ar[$k] = iconv($code, strtoupper(IN_CHARSET).'//IGNORE', pack("H4", substr($v, 2, -1)));
                        }
                }
        }
        return join("", $ar);
}

比如这里

elseif($ac == 'send'){
        $userlogined or exit("{send:-1}");
        $text = unescape(SafeRequest("text","get"));
        $uname = unescape(SafeRequest("uname","get"));
        $uid = SafeRequest("uid","get");
        $setarr = array(
                'in_uid' => $erduo_in_userid,
                'in_uname' => $erduo_in_username,
                'in_uids' => $uid,
                'in_unames' => $uname,
                'in_content' => $text,
                'in_isread' => 0,
                'in_addtime' => date('Y-m-d H:i:s')
        );
        inserttable('message', $setarr, 1);
        echo "{send:1}";
}
        $text = unescape(SafeRequest("text","get"));
        $uname = unescape(SafeRequest("uname","get"));

Saferequest对变量进行addslashes,但是因为做了addslashes之后,又使用了unescape函数进行url解码,所以直接双重编码来绕过addslashes

http://127.0.0.1/xxxxxsourcepluginwebimapijson.php?ac=send&text=%2527%2520%2561%256e%2564%2520%2573%256c%2565%2565%2570%2528%2535%2529%2520%2561%256e%2564%2520%2527%2531%2527%253d%2527%2531&uname=aaa

因为这里是从$_Get接受数据,web服务器会自动进行一次url解码%2527就变成%27,%27在addslashes的时候不会被转义,但是经过addslashes之后,又进入了unescape函数对数据一次url解码,这样%27就被解码成了’,带入sql语句,成功闭合了引号。

最后再举一个字符截断绕过addslashes的案例,这个个人觉得比较有趣

这套系统也是通过addslashes来防御sql注入的

.......
$content=substr(trim($_POST["content"]),0,200);
$face=@$_POST["face"]; 

然后带入sql语句

mysql_query("insert into zzcms_pinglun (about,content,face,username,ip,sendtime)values('$about','$content','$face','$user','$ip','".date('Y-m-d H:i:s')."')");

这个时候有一个比较有趣的绕过思路$_POST[“content”]第两百个字符设置成’,然后被addslashes后就变成’,然后进过substr函数,只截取前两百个字符,留下了,’因为是第201个,所以就没被截取下来。sql语句中'$content','$face',$content后面的内容$face也是可控的,用闭合引号,然后$face就逃出引号造成注入

查看数据库内容,可以看到我们构造的sql语句执行成功了