Python:SQLMap源码精读—基于时间的盲注(time-based blind)
建议阅读
Time-Based Blind SQL Injection Attacks
基于时间的盲注(time-based blind)
测试应用是否存在SQL注入漏洞时,经常发现某一潜在的漏洞难以确认。这可能源于多种原因,但主要是因为Web应用未显示任何错误,因而无法检索任何数据。
对于这种情况,要想识别漏洞,向数据库注入时间延迟并检查服务器响应是否也已经延迟会很有帮助。时间延迟是一种很强大的技术,Web服务器虽然可以隐藏错误或数据,但必须等待数据库返回结果,因此可用它来确认是否存在SQL注入。该技术尤其适合盲注。
源码解释
代码位置:在checkSqlInjection函数中(\lib\controller\checks.py 文件,大约第444行左右)
# In case of time-based blind or stacked queries # SQL injections elif method == PAYLOAD.METHOD.TIME: # Perform the test's request trueResult = Request.queryPage(reqPayload, place, timeBasedCompare=True, raise404=False) if trueResult: # Confirm test's results trueResult = Request.queryPage(reqPayload, place, timeBasedCompare=True, raise404=False) if trueResult: infoMsg = "%s parameter '%s' is '%s' injectable " % (place, parameter, title) logger.info(infoMsg) injectable = True
其中,重点注意Request.queryPage函数,将参数timeBasedCompare设置为True,所以在Request.queryPage函数内部,有这么一段代码:
if timeBasedCompare: return wasLastRequestDelayed()
而函数wasLastRequestDelayed()的功能主要是判断最后一次的请求是否有明显的延时,方法就是将最后一次请求的响应时间与之前所有请求的响应时间的平均值进行比较,如果最后一次请求的响应时间明显大于之前几次请求的响应时间的平均值,就说明有延迟。
wasLastRequestDelayed函数的代码如下:
def wasLastRequestDelayed(): """ Returns True if the last web request resulted in a time-delay """ # 99.9999999997440% of all non time-based sql injection affected # response times should be inside +-7*stdev([normal response times]) # Math reference: http://www.answers.com/topic/standard-deviation deviation = stdev(kb.responseTimes) threadData = getCurrentThreadData() if deviation: if len(kb.responseTimes) < MIN_TIME_RESPONSES: warnMsg = "time-based standard deviation method used on a model " warnMsg += "with less than %d response times" % MIN_TIME_RESPONSES logger.warn(warnMsg) lowerStdLimit = average(kb.responseTimes) + TIME_STDEV_COEFF * deviation retVal = (threadData.lastQueryDuration >= lowerStdLimit) if not kb.testMode and retVal and conf.timeSec == TIME_DEFAULT_DELAY: adjustTimeDelay(threadData.lastQueryDuration, lowerStdLimit) return retVal else: return (threadData.lastQueryDuration - conf.timeSec) >= 0
每次执行http请求的时候,会将执行所响应的时间append到kb.responseTimes列表中,但不包括time-based blind所发起的请求。
为什么?
从以下代码就可以知道了,当timeBasedCompare为True(即进行time-based blind注入检测)时,直接返回执行结果,如果是其他类型的请求,就保存响应时间。
if timeBasedCompare: return wasLastRequestDelayed() elif noteResponseTime: kb.responseTimes.append(threadData.lastQueryDuration)
另外,为了确保基于时间的盲注的准确性,sqlmap执行了两次queryPage。