首页 > 技术文章 > 实验吧因缺思汀的绕过注入解析

nul1 2018-06-14 11:17 原文

 

题目地址:http://ctf5.shiyanbar.com/web/pcat/index.php

我没记错应该是某道CTF比赛的题目

直接上代码:

 1 <?php
 2 error_reporting(0);
 3 
 4 if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
 5     echo '<form action="" method="post">'."<br/>";
 6     echo '<input name="uname" type="text"/>'."<br/>";
 7     echo '<input name="pwd" type="text"/>'."<br/>";
 8     echo '<input type="submit" />'."<br/>";
 9     echo '</form>'."<br/>";
10     echo '<!--source: source.txt-->'."<br/>";
11     die;
12 }
13 
14 function AttackFilter($StrKey,$StrValue,$ArrReq){  
15     if (is_array($StrValue)){
16         $StrValue=implode($StrValue);
17     }
18     if (preg_match("/".$ArrReq."/is",$StrValue)==1){   
19         print "水可载舟,亦可赛艇!";
20         exit();
21     }
22 }
23 
24 $filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
25 foreach($_POST as $key=>$value){ 
26     AttackFilter($key,$value,$filter);
27 }
28 
29 $con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
30 if (!$con){
31     die('Could not connect: ' . mysql_error());
32 }
33 $db="XXXXXX";
34 mysql_select_db($db, $con);
35 $sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
36 $query = mysql_query($sql); 
37 if (mysql_num_rows($query) == 1) { 
38     $key = mysql_fetch_array($query);
39     if($key['pwd'] == $_POST['pwd']) {
40         print "CTF{XXXXXX}";
41     }else{
42         print "亦可赛艇!";
43     }
44 }else{
45     print "一颗赛艇!";
46 }
47 mysql_close($con);
48 ?>

14行定义了一个攻击过滤函数.首先判断了传入的是不是数组,倘若是数组那么就进行分割处理,implode是分割.分割以后的类型仍为数组(因为没有写以什么分割,所以是整体分割,也就是你传aaa结果还是aaa这里的 PS:作用搞不懂他)

然后再是使用了正则过滤,而且是使用了预编译的{$_POST['pwd']} 可参考 :https://www.t00ls.net/viewthread.php?tid=46325

 所以注入是不可能的了.(个人觉得这个预编译可能部分人没注意看会认为是拼接的仍然有注入.所以在这个情况之下会一直话费时间在绕过注入)

加了双引号可以看打是被转义的这就是{$_POST['uname']}的作用

所以综上所述通过or之类的绕过没戏的.


这时就要用到注入的一个小技巧,我们使用group by pwd with rollup 来在查询结果后加一行,并且这一行pwd字段的值为NULL

在mysql官方文档中是这样描述rollup函数的:


大概的意思就是在GROUP BY子句中使用WITH ROLLUP会在数据库中加入一行用来计算总数,ROLLUP子句的更加详细的用法,可以参考mysql的官方文档,此处就不多做赘述了。
再结合limit和offset就可以写出一个payload
即:输入的用户名为:' or 1=1 group by pwd with rollup limit 1 offset 2 #密码为空
这里解释一下此时执行的SQL:
SELECT * FROM interest where uname=' ' or 1=1 
group by pwd with rollup  (在数据库中添加一行使得pwd=NULL)
limit 1 (只查询一行)
offset 2  (从第二行开始查询)
#注释
此时密码只要为空即可查询成功

推荐阅读