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语句中我们可以操作返回结果的方法有:
第一次尝试
尝试通过union构造payload,我们首先要知道目标的表有多少列,从源码里面可以看到就使用了uname、pwd那就当他就只有两个字段吧,多的话在构造就是了。
payload:xxx' union select 1,2;#'
既然可以构造,那就提交参数看看。
将
union
和select
使用大小写混写的方式绕过黑名单
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";#'
发现没有被拦截,但是并没有插入数据。
学习到的新知识
mysql_query
不会执行多条sql语句- 关于派生表的基础知识1
- join、limit offset语句都可以绕过逗号,但是limit offset只针对limit 0,1这样的语句
- from后面不一定要跟表名,也可以是一个数据集,其实表也是一个数据集