php_bugs_04_sql注入关键字过滤绕过——一次失败审计

文章通过分析一个PHP代码示例,展示了如何处理SQL注入问题,特别是如何绕过过滤机制。作者记录了尝试构造payload来规避黑名单过滤的过程,包括使用大小写混写、union和join等方法。尽管尝试未成功,但学习到了mysql_query的限制和派生表等概念。
摘要由CSDN通过智能技术生成

tips:该篇文章没有写正确答案的思路以及流程,网上已经有了。本着从错误中总结经验,该篇文章用来记录自己的错误历程,也分享给有相同经历的朋友们。

php_bugs原项目地址:https://github.com/bowu678/php_bugs.git

sql注入绕过

源码

<?php
error_reporting(0);

if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
    echo '<form action="" method="post">'."<br/>";
    echo '<input name="uname" type="text"/>'."<br/>";
    echo '<input name="pwd" type="text"/>'."<br/>";
    echo '<input type="submit" />'."<br/>";
    echo '</form>'."<br/>";
    echo '<!--source: source.txt-->'."<br/>";
    die;
}

function AttackFilter($StrKey,$StrValue,$ArrReq){  
    if (is_array($StrValue)){

//检测变量是否是数组

        $StrValue=implode($StrValue);

//返回由数组元素组合成的字符串

    }
    if (preg_match("/".$ArrReq."/is",$StrValue)==1){   

//匹配成功一次后就会停止匹配

        print "水可载舟,亦可赛艇!";
        print $ArrReq;
        exit();
    }
}

$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
foreach($_POST as $key=>$value){ 

//遍历数组

    AttackFilter($key,$value,$filter);
}

$con = mysql_connect("127.0.0.1","root","root");
if (!$con){
    die('Could not connect: ' . mysql_error());
}
$db="interest";
mysql_select_db($db, $con);

//设置活动的 MySQL 数据库

$sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql); 

//执行一条 MySQL 查询

if (mysql_num_rows($query) == 1) { 

//返回结果集中行的数目

    $key = mysql_fetch_array($query);

//返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false

    if($key['pwd'] == $_POST['pwd']) {
        print "CTF{XXXXXX}";
    }else{
        print "亦可赛艇!";
    }
}else{
    print "一颗赛艇!";
}
mysql_close($con);
?>

理清思路

逐个遍历POST请求参数,如果输入的是数组则将数组合并,最后再去正则匹配是否存在黑名单字符串。将过了检测后的sql语句拿去执行并且获取一条结果,如果获取的结果与前端输入的pwd相同,则输出flag。

这么一看其实也就是考注入的绕过,然后想办法去构造想要的参数就行。

开始审计

先看看过滤了什么

and|select|from|where|union|join|sleep|benchmark|,|\(|\)

其实直接去看过滤了些什么参数也不是那么重要,重要的是再构造sql注入的时候需要用到哪些参数,然后再去看看哪些被过滤了。其中被过滤的参数,要么使用一些特殊的编码绕过,要么就用其他的语句替代。

然后再看看是怎么去过滤的

preg_match("/".$ArrReq."/is",$StrValue)

发现正则匹配后面跟随有/i说明匹配对大小写敏感,可以采用大小写混写绕过上面过滤的黑名单。

条件一

使用大小写绕过正则匹配黑名单

开始构造payload

根据该条件知道了我们需要sql语句返回的值是我们可以操控的。

在sql语句中我们可以操作返回结果的方法有:

  1. 在select中使用union进行查询【无需苛刻的前提】
  2. 在select中使用join进行表的拼接【可以使用已知的表,也可以使用派生表1
  3. 在insert中使用将特定的字段设置成我们想要的值【例子2
第一次尝试

尝试通过union构造payload,我们首先要知道目标的表有多少列,从源码里面可以看到就使用了uname、pwd那就当他就只有两个字段吧,多的话在构造就是了。

payload:xxx' union select 1,2;#'
请添加图片描述
既然可以构造,那就提交参数看看。
请添加图片描述unionselect使用大小写混写的方式绕过黑名单

payload:xxx' Union sElect 1,2;#'
请添加图片描述发现还是不行,我们拿着这个正则匹配去测试网站3一下。
请添加图片描述发现黑名单里面多过滤了, ( )这三个字符

尝试去绕过一下,这个符号。可以参考join绕过limit offset绕过

因为limit offset绕过仅适用于limit 0,1这样的情况,所以这里采用join方法进行绕过。

payload:xxx' Union sElect * From ((selEct 1)A joIn (select 2)B);#'

请添加图片描述后面仔细看了看发现这里还过滤了( )说明这个方法行不通了,因为interest表有两列,有两列union就必须要逗号或者括号的存在。基本上就是宣布上面说到的关于select中的绕过行不通。

第二次尝试

尝试使用多语句执行对目标表插入数据去实现数据表查询有结果的效果。既然是多语句那就用堆叠注入,又因为不能存在逗号,所以我们要单个单个的去给数据库赋值,或者是只给uname这个字段赋值pwd为空。

payload:xxx';iNsert Into interest sEt uname="xxx";#'
在这里插入图片描述发现没有被拦截,但是并没有插入数据。
请添加图片描述

学习到的新知识

  1. mysql_query不会执行多条sql语句
  2. 关于派生表的基础知识1
  3. join、limit offset语句都可以绕过逗号,但是limit offset只针对limit 0,1这样的语句
  4. from后面不一定要跟表名,也可以是一个数据集,其实表也是一个数据集

其他


  1. 简单的说派生表就是拿着一个结果,并且将结果当成一张表去使用 ↩︎ ↩︎

  2. insert into table1 values(“1”, database());或者使用insert into table1 set xxx=“xxx” ↩︎

  3. https://www.runoob.com/regexp/regexp-syntax.html ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值