目录
0x00 预备 - queryPage()
0x01 bool 型检测策略
判断依据
quick_ratio()
案例
0x02 延时型
判断依据
使用标准差的原因
0xFF 参考:
0x00 预备 - queryPage()
首先先讲一个核心的函数: queryPage(). 这个函数在以下分析中贯穿始终. 其被用于请求页面, 同时具有多种返回值以适配多种检测策略, 见下图:
下面分析一下这几个 return 的情况.
第一个 return:1237 行, 如果传入 timeBasedCompare=True, 则 return wasLastResponseDelayed(), 这个语句会在延时型注入中用到. 函数 wasLastResponseDelayed() 的返回值为一个布尔值, 如果上次请求有延迟则为 True, 反之为 False. 这个函数的具体的实现见延时型检测策略的判断依据部分.
第二个 return:1249 行, 其中 content 和 reponse 都是函数参数传过来的, 默认为 False, 如果为 true 则返回这次请求的响应体, 响应头, 响应码.
第三个 return:1252 行, getRatioValue 也为函数参数传来的, 如果为 True, 则返回一个元组, 两个元素分别为两个 comparison 函数的返回值, 此元组为 (布尔值, ratio)(注: ratio 为两次请求的响应内容的重合率, 被用作判断页面是否变化的依据).comparison 函数被应用在 Bool 型盲注中, 其具体实现逻辑见 bool 型检测策略的判断依据部分.
第四个 return:1254 行, 为上一个 return 的 else 条件, 直接返回 ratio 值.
0x01 bool 型检测策略
首先 bool 型检测之前, 程序会提前检测页面是否稳定 (checkStability()), 即测试两个参数相同的请求的响应是否相同, 如果不同则说明页面中有可能存在类似于时间戳的东西. 如果动态内容对页面改动较大 (ratio<0.98,ratio 为调用 quick_ratio 的值, 此函数原理下方说明), 则调用 findDynamicContent 函数, 去定位页面中动态内容的位置, 并将其定位存在 kb 中.
然后到了 bool 型检测代码段, 先上图
首先看到 475 行调用了 queryPage 函数, 其 payload 参数位置传入了 getCmpPayload(),getCmpPayload 这个函数主要是根据每个 payload 对应的 comparison 标签构造 CmpPayload(用于与 payload 标签进行比较, 比如 payload 为 1=1, 那么 CmpPaload 就是类似为 1=2). 可以看到这一步程序没有取 queryPage 的返回值, 因为其主要作用是设置 threadData 中的 lastPage 之类的值, 用于下一次 True 请求与之比较. 紧接着就会发现 476 行直接把 threadData 的几个 last 变量传给了 falsePage\falseHeaders\falseCode, 方便下面比较.
接着看到 480-482 行发送了 True 逻辑的请求, 并将其响应也赋值给对应的 truePage\trueHeaders\trueCode. 这里 queryPage 的返回值赋值给了 trueResult, 这个函数的返回值已经在第 0 部分中说了, 由于这里没有传入什么多余的参数, 因此进入的是第四个 return, 即一个布尔值, 代表较 ori_page, 这个界面是否发生了变化.
然后在 484 行进行 if 判断, 当 true 与 false 响应不同时进入 (bool 注入可能存在的基础). 进来后再次进行一次 false 判断用于防止误报, 如果 comparison 返回的还是 false, 那就基本上确定为存在漏洞. 反之, 如果这次返回了 True, 与第一次的结果不同, 那么还要进行下一次防止误报, 尝试了解为什么会结果不同.
这就来到了 505 行:
这里的防误报原理主要是提取响应中的文本内容, 然后将响应内容中的纯文本内容拿出来进行单独对比 (即去掉 script,CSS, 注释, html 等标签), 同理, 如果有 True 响应中有而 False 中没有的字符串, 则确认为有漏洞.
然后剩下的 525 行之后, 如果确认存在漏洞需要进行的内容, 就是输出一些 bool 型注入的判断依据字符之类的东西, 这里就不在跟进了. 如下图:
判断依据
comparison() 函数原理:
经查看代码可以发现, 其主要调用的是_comparison(), 因此下面对这个函数进行详细的分析.
首先以 kb.pageTamplate 作为与本次请求对比的响应, 这个变量是程序在初始化阶段调用 checkConnection() 设置的, 其请求中不包含 payload.
然后在根据上面的动态内容位置, 去掉 kb.pageTamplate 和本次请求响应中的动态内容. 见 89-90 行
最后调用 difflib 库的 quick_ratio 方法, 计算两者的页面相似比率, 将之赋值给 ratio. 见 139 行
程序事先定义了两个常量:
- LOWER_RATIO_BOUND==0.02
- UPPER_RATIO_BOUND==0.98
然后设置 kb.matchRatio, 当 ratio 在两者中间时, 程序会将 ratio 赋值给 kb.matchRatio. 见 143-146 行
最后 return 时, 此函数分为了以下几种情况:
1. 当 ratio>0.98 时返回 True, 即判断为页面相同;
2.ratio<0.02 时判断为页面不同;
3.return (ratio - kb.matchRatio)> DIFF_TOLERANCE(0.05),kb.matchRatio 是一个在 0.02 与 0.98 之间的值, 在上面已经说了, 是在一次请求中使用 ratio 赋值的. 这个 return 的判断可以转换成 ratio>kb.matchRatio+0.05, 也就是说 ratio 必须大于之前的一次 ratio 至少 0.05 才行, 同时如果 ratio>0.98 也是直接返回 True 的 (第一次的条件).
quick_ratio()
统计字符的个数 (比如字母 a 有 29 个等等), 然后拿匹配的字母数 * 2 / 两个对比字符串的字符总数
案例
下面看一下在使用正确的 boundary 突破边界之后, True 请求和 False 请求的最终对比界面是什么.
首先是一个正常请求的响应 (www.test.com/index.PHP?id=2):
第一个框是直接返回 url 中的参数值, 即 id=2.
第二个框是时间戳, 即保证在每次响应这一部分都是变化的.
第三个框是 "you are in", 表示可以在数据库中找到数据, 看一下源码:
下面先看一下 True 请求的响应.
可以看到, 第一个框处只有 id=, 没有 id 的值, 这是因为在进行对比之前, 为了避免 "payload 本身就是不同的" 这种影响, 实现就已经去掉了这些反射型的参数 (类似于 xss, 即页面直接返回了用户可控的参数).
再 False 的响应.
这里也没有第一个框, 跟 True 响应的情况相同. 同时这里也没有第三个框, 因为这个 False 语句构建了一个逻辑假的 SQL 语句, 直接导致程序无法在数据库中找到数据.
0x02 延时型
598 行开始进行延时型判断, 600 行调用 queryPage 函数, 返回值为一个布尔值, True 表示这次请求产生了延迟 (见'判断依据'部分),code 为 http 响应码.
接着进入 603 行的 if 语句, 如果上次存在延时则进入 (由于 payload 中使用了 [SLEEPTIME], 在 queryPage 中将之替换成了一个值, 所以如果存在漏洞则一定会有延时).
如果进入了这个语句块则再次进行一次时延时间为 0 的请求, 如果还是产生时延则说明为误报. 如果没有时延则在 611 行再进行一次有时延时间的请求, 结果如果还是 True(与 603 行结果一致), 则确定为存在漏洞.
判断依据
判断本次请求是否产生延迟调用的是 wasLastResponseDelayed 函数, 先放个图:
可以看到, 首先计算标准差: deviation. 然后在 2402 行计算 lowerStdLimit, 值为平均数 + 7 * 标准差, 以这个值看做一个阈值, 作为最大延迟时间 (小于 0.5 时看做 0.5). 大于这个数的请求都看做是发生延时的请求.+-7 * 标准差能保证 99.9999999997440% 的未延时请求能落在这个区间里.
使用标准差的原因
为什么不是平均值呢, 因为标准差更能反映一组数据的离散程度. 比如熊的平均体重是 140kg, 标准差为 5kg, 那么一只熊的重量可能在 135-145kg(根据标准差计算) 之间, 也有可能在 120-160kg(根据平均数猜测) 之间. 因此仅仅查看所有熊的平均重量就不可能知道单个熊的重量, 但是标准差可以告诉你单个熊的可靠重量范围. 这就是这里使用标准差的意义.
参考:
1.How Self-Tuning Threshold Baseline is Computed
2. 标准差的意义
0xFF 参考:
sqlmap 检测剖析 -- 凤雏 https://paper.seebug.org/729/#_8
Python:SQLMap 源码精读 - 基于时间的盲注 (time-based blind) -- 曾是土木人
sqlmap time-based inject 分析 -- 美丽联合 SRC https://www.freebuf.com/column/168112.html
sqlmap 基于时间盲注判断原理 -- think_ycx
Sqlmap 如何检测 Boolean 型注入 -- lufei https://www.anquanke.com/post/id/167408
sqlmap 中文手册 -- werner-wiki
超详细 SQLMap 使用攻略及技巧分享 https://www.freebuf.com/sectool/164608.html
来源: https://www.cnblogs.com/litlife/p/10693582.html