SQLMap源码分析 前置发包中的WAF检测
sqlmap前置发包
在sqlmap检测sql注入点的过程中,会有一系列前置发包,这些前置发包主要包括
- 网站连通性检测
- WAF探测
- 网页稳定性检测
- 参数动态性检测
- 启发式注入检测
- 误报检测
这里着重于WAF
检测源码的分析,但提到WAF探测
不得不提到网页相似度对比
网页相似度对比
虽然名字没咋听过,不过其实很容易理解,简单举个例子:
在使用自动化注入的过程或者使用扫描器的过程中,如何判断当前遇到了防火墙
稍作思考其实就能够知道,我们可以通过检测正常网页和传递了payload
网页两者返回状态的不同判断是否遇到了waf
比较简单的方式是直接看返回网页的状态码,如果为404或者响应超时肯定就遇到了waf
稍微好一点的方式是计算正常网页的md5
值和传递了payload
的网页的md5
值,不过这个方法过于鸡肋,因为不管是相同还是不同,你都不能判断是否存在漏洞或是遇到了waf
,因为页面稍有不同就会导致md5
计算的不一致
更好一点的方法就是一些很出名的计算页面相似度的算法了,我们可以直接拿来用,比如tf-idf算法
,余弦相似度计算
,simhash
等等,各有优劣,可以根据不同的应用场景进行选取
在sqlmap
中使用difflib
这个模块来进行页面相似度的对比,实际处理的时候,sqlmap 并不仅仅是直接计算页面的相似度,而是通过首先对页面进行一些预处理,预处理之后,根据预设的阈值来计算请求页面和模版页面的相似度。比如说,我们设定一个阈值0.8
,如果输入payload
之后网页与正常网页的相似度计算后大于0.8
,即强相关,我们则认定没有遇到waf
。
在difflib
模块中存在ratio()
方法,该方法返回两段文本的相似度,相似度的算法如下:我们假设两段文本分别为 text1
与 text2
,他们相同的部分长度总共为 M
,这两段文本长度之和为 T
,那么这两段文本的相似度定义为 2.0 * M / T
,这个相似度的值在 0 到 1.0 之间
一般来说针对某一类型漏洞,其页面相似度的阈值是需要对不同页面大量测试之后取相对稳定的值,sqlmap
的编写人员根据他们的算法和测试取值为0.02-0.98
,因为该算法不是本文的重点,在此处略过
sqlmap注入流程
WAF检测部分
waf
检测代码在checkWaf()
方法中,在start()
方法中,sqlmap
初始化完成后就会开始检测防火墙
checkWaf()
if conf.nullConnection:
checkNullConnection()
checkWaf()
函数的注释信息有:
@stackedmethod
def checkWaf():
"""
Reference: http://seclists.org/nmap-dev/2011/q2/att-1005/http-waf-detect.nse
"""
该检测waf
的方法实际上来自NMAP的http-waf-detect.nse
:https://seclists.org/nmap-dev/2011/q2/att-1005/http-waf-detect.nse
比如页面为index.php?id=1
,那现在添加一个随机变量index.php?id=1&aaa=2
,设置paoyload类似为AND 1=1 UNION ALL SELECT 1,2,3,table_name FROM information_schema.tables WHERE 2>1-- ../../../etc/passwd
,如果没有WAF,页面不会变化,如果有WAF,因为payload中有很多敏感字符,大多数时候页面都会变成waf防护页面。
sqlmap
中构造的payload
为
payload = "%d %s" % (randomInt(), IPS_WAF_CHECK_PAYLOAD)
其中IPS_WAF_CHECK_PAYLOAD
在settings.py
文件中,为
IPS_WAF_CHECK_PAYLOAD = "AND 1=1 UNION ALL SELECT 1,NULL,'<script>alert(\"XSS\")</script>',table_name FROM information_schema.tables WHERE 2>1--/**/; EXEC xp_cmdshell('cat ../../../etc/passwd')#"
经过一系列处理后发送payload
try:
retVal = (Request.queryPage(place=place, value=value, getRatioValue=True, noteResponseTime=False, silent=True, raise404=False, disableTampering=True)[1] or 0) < IPS_WAF_CHECK_RATIO
except SqlmapConnectionException:
retVal = True
finally:
kb.matchRatio = None
此处的IPS_WAF_CHECK_RATIO
# Ratio used in heuristic check for WAF/IPS protected targets
IPS_WAF_CHECK_RATIO = 0.5
sqlmap
检测到与原始请求响应相似度小于0.5时,认为存在WAF。
如果出现except
比如超时,也证明存在注入
其流程为:
小记
以前的sqlmap
有waf
文件夹,里面包含了一些44种常见的防火墙特征
其流程为:
在sqlmap中检测waf的方式是传入一个网址,获取网址内容与头部信息,然后检测是否存在该waf的特征值,如果存在,就让retval为真并且返回这个值
判断waf
特征值则是利用正则表达式实现的,比如:
'yunsuo':[
'retval = re.search(r"<img class=\"yunsuologo\"", page_get, re.I)',
'retval = re.search(r"yunsuo_session",headers_get, re.I)'
]
来判断目标是否受云锁
的保护
但是这种方式的局限性在于无法涵盖所有的waf
,sqlmap
的开发人员应该也是考虑到这一点去除了waf
文件夹,使用页面相似度来判断是否存在防火墙
现在的检测思路为:
构造恶意payload -> 检查响应 -> 检查相似度 -> 判断WAF