贷乐高注入复现

Jun 11, 2018 09:54 · 489 words · 3 minute read 渗透

这篇文章主要介绍了一种绕过waf的思路技巧。在于拓展思维。由于没有找到源码,所以就记录一下这个思路技巧。

部分代码

/core/sqlin.inc.php,包含在config.inc.php中,所有请求都会经由此类过滤:

class sqlin {
	function dowith_sql($str) {
		$check= eregi('select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile', $str);
		if($check)
			{
			echo "非法字符!";
			exit();
		}
		
		$newstr="";
		while($newstr!=$str){
		$newstr=$str;
        $str = str_replace("script", "", $str);
        $str = str_replace("execute", "", $str);
        $str = str_replace("update", "", $str);
        //$str = str_replace("count", "", $str);
        //注释掉对count的过滤,不然account这样的参数会被截断
        $str = str_replace("master", "", $str);
        $str = str_replace("truncate", "", $str);
        $str = str_replace("declare", "", $str);
        $str = str_replace("select", "", $str);
        $str = str_replace("create", "", $str);
        $str = str_replace("delete", "", $str);
        $str = str_replace("insert", "", $str);
        $str = str_replace("\'", "", $str);
        
		}
		return $str;
    }
	
//aticle()防SQL注入函数//php教程
    function sqlin() {
		
        foreach ($_GET as $key => $value) {
			//echo $key."|".(strpos($key, "password") == false);
            if ($key != "content"&&strstr($key, "password") == false) {
                $_GET[$key] = $this->dowith_sql($value);
            }
        }
        foreach ($_POST as $key => $value) {
			//echo $key."|".(strpos($key, "password") == false);
			[email protected]_put_contents('wxy123123.txt', date('Ymd His') . '提交url拼接 '.$key."|".(strstr($key, "password") == false), FILE_APPEND);
            if ($key != "content"&&strstr($key, "password") == false) {
                $_POST[$key] = $this->dowith_sql($value);
            }
        }
		foreach ($_REQUEST as $key => $value) {
			//echo $key."|".(strpos($key, "password") == false);
            if ($key != "content"&&strstr($key, "password") == false) {
                $_REQUEST[$key] = $this->dowith_sql($value);
            }
        }
    }
}

/core/safe.inc.php部分代码

/* 检查和转义字符 */
function safe_str($str){
    if(!get_magic_quotes_gpc()) {
        if( is_array($str) ) {
            foreach($str as $key => $value) {
                $str[$key] = safe_str($value);
            }
        }else{
            $str = addslashes($str);
        }
    }
    return $str;
}

function dhtmlspecialchars($string) {
    if(is_array($string)) {
        foreach($string as $key => $val) {
            $string[$key] = dhtmlspecialchars($val);
        }
    } else {
        $string = str_replace(array('&', '"', '<', '>','(',')'), array('&amp;', '&quot;', '&lt;', '&gt;','(',')'), $string);
        if(strpos($string, '&amp;#') !== false) {
            $string = preg_replace('/&amp;((#(\d{3,5}|x[a-fA-F0-9]{4}));)/', '&\\1', $string);
        }
    }
    return $string;
}

foreach ($_GET as $key => $value) {
    $_GET[$key] = safe_str($value);
    $_GET[$key] = dhtmlspecialchars($value);
}
foreach ($_POST as $key => $value) {
    $_POST[$key] = safe_str($value);
    $_GET[$key] = dhtmlspecialchars($value);
}
foreach ($_REQUEST as $key => $value) {
    $_REQUEST[$key] = safe_str($value);
    $_REQUEST[$key] = dhtmlspecialchars($value);
}
foreach ($_COOKIE as $key => $value) {
    $_COOKIE[$key] = safe_str($value);
    $_GET[$key] = dhtmlspecialchars($value);
}


两段代码的作用

第一段代码对\$_GET,\$POST,\$_REQUEST都进行了过滤,过滤正则是select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile这个正则只是一部分,只要被这个正则匹配到,程序就会exit; 继续往下,还有针对关键字的替换。(delete,update等等)

第二段代码是对\$_GET,\$POST,\$_REQUEST,\$_COOKIE中的一些特殊字符做转义和替换。还会将英文的()替换为中文的(),很鸡儿骚。

梳理逻辑

贷乐高cms对于参数的处理的流程大致过程如下:

index.php->config.inc.php->sqlin.php->safe.inc.php

sqlin.php是对关键字的拦截,safe.inc.php是替换一些敏感字符。

在safe.inc.php中还有这样一段代码

$request_uri = explode("?", $_SERVER['REQUEST_URI']);
if (isset($request_uri[1])) {
	$rewrite_url = explode("&", $request_uri[1]);
	foreach ($rewrite_url as $key => $value) {
		$_value = explode("=", $value);
		if (isset($_value[1])) {
			$_REQUEST[$_value[0]] = dhtmlspecialchars(addslashes($_value[1]));
			//$_REQUEST[$_value[0]] = addslashes($_value[1]);
			//$_REQUEST[$_value[0]] = dhtmlspecialchars($_value[1]);
		}
	}
}

这段代码是将\$_SERVER[‘REQUEST_URI’]中的内容做了一次过滤,然后赋值给\$_REQUEST[]数组。

这段代码是绕过waf的关键所在。这段代码会重新对\$_REQUEST[]数组赋值,\$_REQUEST[]数组是包含了\$_GET和\$_POST数组的。

绕过

绕过思路

假设第一道waf在检测参数时没有检测到参数,然后在第二段waf处利用处理\$_SERVER[‘REQUEST_URI’]的代码对\$_REQUEST[]数组的值进行了覆盖。那么就可以绕过waf了。

那么怎么才能在第一道waf不检测到恶意字符呢? 这个问题很严肃,因为waf对数组的每个值进行检测,只要有一个出现问题,程序就会终止。

php的两个个特性

两个参数取后一个

实际测试一下,就知道这个特性了。

<?
$a = $_REQUEST['yy'];
echo $a;
?>

测试

http://127.0.0.1/45.php?yy=1111

输出 1111

http://127.0.0.1/45.php?yy=1111&yy=2222

输出2222


当url里的参数重复时,php会采用后一个参数。这是HTTP Parameter Pollution在php中的表现。

有了这个特性,那么是不是就尝试让waf检测的是第二个参数,而到覆盖REQUEST的时候使用第一个参数。

如果直接使用相同的参数是不可行的,两道waf取的参数都是第二个参数。

解析特性,转换.为_

这里可以利用php的另一个特性:php自身在解析请求时,如果参数中包含. [这几个字符,会将他们转换为下划线。

<?php  
$url = explode("?",$_SERVER['REQUEST_URI']);
echo "<pre>";
print_r($url);
echo "</pre>";

echo "<pre>";
print_r($_REQUEST);
echo "</pre>";

输出

url: http://127.0.0.1/45.php?yy=1111&yy.id=2222
Array
(
    [0] => /45.php
    [1] => yy=1111&yy.id=2222
)
Array
(
    [yy] => 1111
    [yy_id] => 2222
)

可以看到输出的为yy_id,而url中为yy.id。

### 结合 构造一个两个特性结合在一起的url

http://127.0.0.1/45.php?yy_id=1111&yy.id=2222

这样的url在第一道waf时检测时,\$_REQUEST获取到的是2222,在第二段waf处理\$_SERVER[‘REQUEST_URI’]时,因为yy_id和yy.id是两个不同的字符串,所以最后的\$_REQUEST[yy_id]就为1111.

测试

<?php  
echo "第一段waf:";
echo $_REQUEST["yy_id"];
echo "<br>";
$request_uri = explode("?", $_SERVER['REQUEST_URI']);
if (isset($request_uri[1])) {
	$rewrite_url = explode("&", $request_uri[1]);
	foreach ($rewrite_url as $key => $value) {
		$_value = explode("=", $value);
		if (isset($_value[1])) {
			$_REQUEST[$_value[0]] = addslashes($_value[1]);
		}
	}
}
echo "第二段waf:";
echo $_REQUEST["yy_id"];
?>

输出结果

http://127.0.0.1/45.php?yy_id=1111&yy.id=2222

第一段waf:2222
第二段waf:1111

这样就绕过了waf的检测。

利用

从上面的内容来看,这个漏洞的利用需要满足以下几个条件 - 有注入点 - 注入点由$REQUEST中获取。 - 变量的名字包含下划线 - 不使用特殊字符(第二段waf会对特殊字符转义,可以union select注入完全不需要括号什么的)

这几个条件在这个贷齐乐cms里很好找,因为该cms过分相信于waf,内部存在太多注入。

来源

tweet Share