SQLMap原理分析(二)

SQLMap原理分析(一)通过SQLMap的请求进行了一次简单的分析,大概了解SQLMap一个粗略的运行流程。这次通过源码的Debug进行深入一点研究。

准备

这里使用pycharm进行debug,打开SQLMap项目之后,在【Run】-【Edit Configurations】设置参数:-u http://testasp.vulnweb.com/showforum.asp?id=0 –flush-session。由于上次跑了testasp这个站点有缓存因此加上了–flush-session。

pycharm-config.png

Debug

连接检测

准备工作做好之后,在sqlmapy.py文件第407行下一个断点,然后开启Debug之旅。

debug-1.png

可以看到现在已经成功断到407行了,单步步入到main()函数中。发现前面几行代码是获取配置、路径、banner等信息。当运行到136行的时候可以发现已经获取到前面设置的站点参数。

debug-2.png

运行到156行步入到init()函数中,2629行至后面可以看到会进行一系列设置:http、threads等等。

debug-3.png

步出回到sqlmapy.py中的main函数,继续单步运行会进行一系列判断检查,直到177行会发现start函数,步入到start函数。这时候会来到./lib/core/decorators.py的stackedmethod函数,根据注释,该函数是用来堆栈对齐的回退函数(不太理解啥意思)。看到result关键字直接步入。

debug-4.png

发现来到./lib/controller/controller.py的start函数。根据注释可以得知,该函数用来检查url、请求方式、cookie以及是否存在注入等。

debug-5.png

经过一系列的信息获取:Method、paramKey、Headers等,来到了420行进行连接等检查。

debug-6.png

跟进checkConnection函数,会来到./controller/checks.py。先检查hostname是否是ip形式(xxx.xxx.xxx.xxx),之后检查有没有设置代理。然后输出log信息:尝试连接目标url。

debug-7.png

终端上这时候print出该条日志信息。

log-print.png

在1589行可以看到开始进行request请求,跟进Request函数,来到./request/connect.py,通过注释可以得知queryPage函数是用来获取目标url页面内容。

debug-8.png

直到1306行调用Connect.getPage发起请求开始获取页面内容。

debug-9.png

步入getPage函数,经过一系列的赋值:url、get类型参数、cookie等。

debug-10.png

497行调用urllib.request.urlopent发起请求。

debug-11.png

515行获取响应正文信息,这跟上篇文章请求第一个请求包相呼应。

debug-12.png

570行会关闭连接。

debug-13.png

最后getPage函数会return出响应正文、响应头以及响应状态码。继续运行回到queryPage函数,经过一系列处理queryPage函数将响应正文、响应头以及响应状态码也return出去。

debug-14.png

之后会来到./lib/core/decorators.py,会将获取到的result返回。

debug-15.png

会回到checks.py,最终返回True。这时候SQLMap已经获知目标站点可连接。

debug-16.png

WAF判断

之后会开始进行WAF检测&识别。

检测

在423行进行waf检测。

debug-17.png

跟进checkWaf函数,又会来到stackedmethod函数,直接到在result进行步入,会来到checkWaf函数。根据注释可以得知sqlmap的waf检测能力来源nmap的http-waf-detect脚本。

debug-18.png

首先将几种攻击类型的payload(SQL注入、目录遍历、XSS等)拼接到已有参数发起请求。

debug-19.png

如果直接连接错误,可以判断存在WAF。若可正常连接,判断不存在WAF。

debug-20.png

识别

继续执行可以看到identifyWaf函数,但由于并未设置检测waf会被判断跳过。可以按住command点击identifyWaf函数跟进查看原理。大概原理是调用waf文件夹下脚本进行检测-得到结果。脚本脚本大概逻辑为:发起请求-获取响应正文、响应头、响应码-根据规则判断-返回结果。

debug-21.png

稳定性检测

回到controller运行至436行会有checkStability函数。

debug-22.png

跟进该函数,通过备注发现该函数是用来进行稳定性检测。

debug-23.png

参数动态检测

经过一系列赋值&判断,运行至535行步入checkDynParam函数,根据注释可以得知该函数是用来检测参数是否为动态。

debug-24.png

注入检测

简单判断

运行至558行,终于来到关键的注入检测。跟进heuristicCheckSqlInjection函数,在1023行进行随机字符串获取,随机字符串长度为10。并且该随机字符串需满足单引号或者双引号出现次数为1。

debug-25.png

接下来将随机字符串拼接成payload,发起请求。这个请求跟上篇文章请求中的注入判断请求包对应。

debug-26.png

1035行调用parseFilePaths函数检测响应正文中是否包含绝对路径。

debug-27.png

1036行检测上一个响应是否有数据库错误信息,这时候的上个请求payload是包含单双引号的,通过这种方式可以极快的判断是否存在注入。

debug-28.png

由于这里并不会有数据库的报错信息,所以还需要继续运行。在1092行会生成两个随机变量,长度为6。接下来生成带<’">的payload,该payload为第一个随机字符串加上<’">加上第二个随机字符串。

debug-29.png

1095行出现agent.payload函数,跟进该函数(./lib/core/agent.py),根据注释得知该函数功能是替换SQL注入参数。

debug-30.png

166行调用cleanupPayload函数,根据函数名猜测该函数主要是用来进行payload清理。

debug-31.png

最终返回经过处理之后的payload:
u'id=__PAYLOAD_DELIMITER__0\'ozeyed<\'">cOuFpj__PAYLOAD_DELIMITER__'

debug-32.png

之后使用处理之后的payload发起请求。

debug-33.png

最后返回kb.heuristicTest。

debug-34.png

继续运行回到start函数,570行调用checkSqlInjection开始进行注入检测。

debug-35.png

跟进checkSqlInjection函数,调用InjectionDict函数设置注入字典,之后对参数值类型进行检查。

debug-36.png

135行调用getSortedInjectionTests函数获取待注入类型及其payload等信息。142行会将tests数据取出来,直至取完才能跳出141行的while循环。

debug-37.png

148行由于条件并不满足,会跳过dbms检测。

debug-38.png

之后对payload进行处理,直至506、511行调用Request.queryPage请求。这时候的payload包含AND关键字。

debug-39.png

之后对结果进行判断,由于并没有满足条件,许多判断都直接pass掉。开始重新构造payload发起请求。直至payload为boolen类型注入,会进入判断设置injectable = True。

debug-40.png

拆分一下这里的判断逻辑:

  1. falsePage与truePage是否相等,falsePage使用的payload为cmpPayload、TruePage使用的payload为reqPayload。假设得到结果为A,A为布尔类型;
  2. 获取not kb.nullConnection结果,假设得到结果为B,B为布尔类型;
  3. 判断not(A and B),假设得到结果为C,C为布尔类型;
  4. 判断trueResult and C,假设得到结果为D,只有trueResult、C同为True。D才能为True,满足条件判断;
  5. 正常情况下B为True,这时候只有falsePage不等于truePage,才能满足条件。

debug-41.png

这时候的判断还是比较简单的判断并不能直接就认为该处存在注入,可以看到终端输出时该处似乎是布尔类型的盲注。

debug-42.png

之后对该注入信息进行赋值存储injection变量中。由于这时候injectable为True,所以会跳出372行的for循环。

debug-43.png

深度判断

待定。

总结

SQLMap整个运行机制:

  1. 获取url、thread、headers等信息存储至变量中;
  2. 网站存活性检测;
  3. WAF检测&WAF类型识别;
  4. 稳定性检测;
  5. 注入检测。

SQLMap关键的脚本:

  1. ./lib/core/decorators.py
  2. ./lib/controller/controller.py
  3. ./request/connect.py
  4. ./controller/checks.py
  5. ./lib/core/agent.py

通过SQLMap机制简单分析,后续在手工注入的时候可以参考SQLMap的判断机制。