【sql-labs】闯关记录21~25
【less-21】基于cookie的注入(base64加密)
1、测试流程
这一关和第20关很像
先登录进去
点击delete用burp抓包:
发现cookie字段像是被加密了,看到了%3D(=的十六进制),应该是base64加密。
于是构造payload:1' and 1=2 union select user(),database(),version()#
用base64编码为:MScgYW5kIDE9MiB1bmlvbiBzZWxlY3QgdXNlcigpLGRhdGFiYXNlKCksdmVyc2lvbigpIw==
插入payload | 报错,发现是用’)闭合的 |
---|---|
于是更改payload:1') and 1=2 union select user(),database(),version()#
用base64编码为:MScpIGFuZCAxPTIgdW5pb24gc2VsZWN0IHVzZXIoKSxkYXRhYmFzZSgpLHZlcnNpb24oKSM=
重新插入payload | 成功! |
---|---|
2、源码分析
与上一关的不同之处在于对cookie字段进行了base64编码,解决方法就是直接对payload的进行base64编码后再去替换cookie。还有一个就是闭合方式不同,上一关使用单引号,这一关使用’)
【less-22】基于cookie的注入(base64加密)
与less-21相比,只是闭合方式的不同,less-22使用"闭合的,其他的与less-21一样。
从报错中判断出后端闭合方式为"
插入编码后的payload | 成功爆出数据库信息 |
---|---|
【less-23】注释符过滤
1、测试流程
先输入一个单引号,发现报错:
从报错信息来看,后端使用单引号来闭合的
1' and 1=1--+
依然报错,说明后面的–+并没有起作用。
于是想到万能密码那一招:1' and 1='1
果然有用,哈哈!接着开搞!
- 试一下报错注入:
?id=1' and updatexml(1,concat(0x7e,user()),1) and 1='1
成功!
-
试一下union注入
先order by查询主查询的字段数
结果order by到了10000还不报错???
看了大佬文章,很有收获。是后端对select语句处理顺序的问题,
select * from users where id=1 order by 100 and 1=1
,后端先会去执行where后面的语句id=1
, 然后才会执行order by 100
结果发现并没有找到100,就会向主句返回一个false,然后继续执行and 1=1
向主句返回为true,将原来的false给顶掉了,所以语句正常执行。看来order by不行,只能靠手动去猜了
一直试到3,回显正常。结果发现password字段回显并不是3,而是1。换了各种字段试了多次,password字段总是显示1或0。
于是去数据库看一下:
原来是sql将
'5' and 1='1'
当作一个字段去处理了,所以只有两个值真或假也就是0或1。不过还是可以利用第二个字段去暴库的
暴库方式与之前相似,这里就不再赘述。
2、源码分析
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
// take the variables
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); //这里对sql注释符进行了过滤
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo '<font color= "#0000ff">';
echo 'Your Login name:'. $row['username'];
echo "<br>";
echo 'Your Password:' .$row['password'];
echo "</font>";
}
else
{
echo '<font color= "#FFFF00">';
print_r(mysql_error());
echo "</font>";
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>
preg_replace()
函数:执行一个正则表达式的搜索和替换。
$reg1 = "/--/"
:这头尾两个斜杠/是正则表达式的限定符,这是Perl正则的标准,而php支持的正则表达式就是Perl正则的规范。表示两个斜杠之间就是正则内容,在结尾斜杠后面可以开启匹配的模式,例如:/–/i ,后面的 i 就是忽略大小写匹配。
由上面代码可知,后端对sql注释符进行了过滤,这里可以使用万能密码的方式绕过。
【less-24】二次注入
1、测试流程
在每个界面都尝试了多次,都失败了
查看后端源代码,发现所有的参数都被转义了,一般的攻击思路好像没有作用
参考了大佬文章,发现一种新思路:
二次注入:通俗的来说就是攻击者精心构造SQL语句插入到数据库中,插入到数据库中的payload被其他类型的SQL语句调用的时候触发攻击行为。因为第一次攻击者插入到数据库的时候并没有触发危害性,而是再其他语句调用的时候才会触发攻击行为,这就是二次注入。
先创建一个用户名为admin'#
开头的用户类似于admin'#333
、admin'#pika
等等。
注册成功后,此时后台会将admin'#hacker
插入到数据库中,去数据库查看一下:
然后我们用新注册的账号去登录,登陆成功后去修改密码:
这个操作,在后端数据库的拼接逻辑是这样的:
UPDATE users SET PASSWORD='$pass' where username='admin'#hacker' and password='$curr_pass'
所以相当于直接修改了admin用户的密码
我们到数据库查看一下:
发现确实已被修改。
2、源码分析
-
index.php没啥敏感代码
检测会话,若session中有username参数,并且cookie中有Auth参数的话就会跳转到logged-in.php
下方有个表单提交给login.php
表单中有login_user输入框和login_password输入框,两个超链接一个是忘记密码跳转到forgot_password.php,另一个是注册用户跳转到new_user.php
//index.php
<?PHP
session_start();
if (isset($_SESSION['username']) && isset($_COOKIE['Auth'])) {
header('Location: logged-in.php');
}
?>
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
?>
-
logged-in.php
用来修改密码
检测会话:若session中没有username参数或cookie中没有username参数,页面都会跳转到index.php
一个表单提交到pass_change.php:
表单中有current_password输入框当前密码、password输入框新密码、re_password输入框确认密码
-
pass_change.php
用来更新数据库密码
检测会话:若session中没有username参数或cookie中没有username参数,页面都会跳转到index.php
用
mysql_real_escape_string()
将用户输入参数值进行转义,然后进行数据库的密码更新操作if 更新成功{ echo "Password successfully updated"; } else{ header('Location: failed.php'); //如果更新失败则重定向到failed.php }
-
failed.php
检测会话:若session中没有username参数或cookie中没有username参数,页面都会跳转到index.php
-
new_user.php
用来注册用户
一个表单提交到login_create.php
表单中有username、password、re_password三个输入框
-
login_create.php
先验证用户名是否已经存在,若存在则返回The username Already exists, Please choose a different username
若用户名不冲突,则判断两次输入的密码是否一致
若一致,则插入到数据库中,用户参数部分有\转义
【less-25】
1、测试流程
先输入一个1看看:
测试引号闭合问题:
测试单引号 | 测试双引号 |
---|---|
从以上回显分析,应该是单引号注入。
接下来就要考虑绕过了:
1、首先判断过滤是一次性还是非一次性的:
若是一次性的,且只是将过滤字符换成了空字符,那就可以通过双写绕过:
or=oorr、and=anandd
若是非一次性的,就要考虑一些变形:
大小写变形绕过-----or=Or=oR=OR
利用运算符-------or=||、and=&&
URL编码绕过-------#=%23、Hex编码--------~=0x7e
添加注释------------/*or*/
…
2、然后如果是url中,空格和一些特殊字符会进行url编码,比如:#是%23、空格是%20
?id=1’#将会报错,要写成?id=1’%23才不会报错,而且我们也可以使用-- #或–+或–空格加任意非空格字符
输入?id=1' aandnd 1=1--+
回显正常。
输入?id=1' aandnd 1=2--+
回显为空,说明双写绕过(当然也可以选择运算符绕过)奏效了。
暴字段数:?id=1' oorrder by 3--+
order by试出主查询字段数为3
接着就是脱裤了:
流程与前面相似,这里就不再赘述了。
2、源码分析
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
//fiddling with comments
$id= blacklist($id);
//echo "<br>";
//echo $id;
//echo "<br>";
$hint=$id;
// connectivity
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo "<font size='5' color= '#99FF00'>";
echo 'Your Login name:'. $row['username'];
echo "<br>";
echo 'Your Password:' .$row['password'];
echo "</font>";
}
else
{
echo '<font color= "#FFFF00">';
print_r(mysql_error());
echo "</font>";
}
}
else
{
echo "Please input the ID as parameter with numeric value";
}
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;
}
?>
由源码可以看到对用户的输入做了正则匹配过滤,不区分大小写的过滤了or和AND。但是只是匹配一次,所以可以双写绕过。
使用双写可以绕过、运算符可以绕过(&&需要url编码为%26%26)。
参考大佬文章