文章目录
sqlmap
一、概述
sqlmap是一个开源渗透测试工具,它可以自动检测和利用 SQL 注入漏洞并接管数据库服务器。它具有强大的检测引擎,同时有众多功能,包括数据库指纹识别、从数据库中获取数据、访问底层文件系统以及在操作系统上带内连接执行命令。
支持的数据库有:
MySQL, Oracle, PostgreSQL, Microsoft SQL Server, Microsoft Access, IBM DB2, SQLite, Firebird, Sybase和SAP MaxDB
二、基本参数
1、判断可注入的参数
2、判断可以用哪种SQL注入技术来注入
3、识别出哪种数据库
4、根据用户选择,读取哪些数据
1. 检测注入点
-u "url"
sqlmap -u "http://192.168.40.129/PHP/sqli-labs-master/Less-1/?id=1"
sqlmap支持五种不同的注入模式:
1、基于布尔的盲注,即可以根据返回页面判断条件真假的注入。
2、基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。
3、基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。
4、联合查询注入,可以使用union的情况下的注入。
5、堆查询注入,可以同时执行多条语句的执行时的注入。
2. 列出所有数据库名
--dbs
sqlmap -u "http://192.168.40.129/PHP/sqli-labs-master/Less-1/?id=1" --dbs
3. 列出当前数据库名
--current-db
sqlmap -u "http://192.168.40.129/PHP/sqli-labs-master/Less-1/?id=1" --current-db
4. 列出数据库名表名
-D 指定一个数据库
--tables
sqlmap -u "http://192.168.40.129/PHP/sqli-labs-master/Less-1/?id=1" -D "security" --tables
5. 列出表中字段名
-T 指定表名
--columns
sqlmap -u "http://192.168.40.129/PHP/sqli-labs-master/Less-1/?id=1" -D "security" -T "users" --columns
6. 列出字段内容
-C 指定字段
--dump
sqlmap -u "http://192.168.40.129/PHP/sqli-labs-master/Less-1/?id=1" -D "security" -T "users" -C "username,password" --dump
- 读取post请求
使用bp抓包,将http信息保存为文件,使用sqlmap读取
抓包结果:
将结果保存为post.txt文件
-r 文件
sqlmap -r post.txt
三、sqlmap简单原理分析
- 测试环境
1.5.1.6版本的sqlmap;
使用 AWVS 提供的环境:
http://testphp.vulnweb.com 或 http://testasp.vulnweb.com
- 测试
debug分析sqlmap源码
这里使用 IDEA 进行 debug,打开 SQLMap 项目之后,在【Run】-【Edit Configurations】设置参数:
-u http://testasp.vulnweb.com/showforum.asp?id=0 --flush-session
刷新session缓存
--flush-session
在 sqlmapy.py 文件的main方法下一个断点,然后开启 Debug:
1. 初始化&与目标站点建立连接
当进入main方法后:
发现main方法的前面几行代码是获取配置、路径、banner 等信息;当运行到 153 行的时候可以发现已经获取到前面设置的站点参数并进入initOptions () 函数(初始化选项)中:
def initOptions(inputOptions=AttribDict(), overrideOptions=False):
# 此函数将一些所需的属性设置为配置单例
_setConfAttributes()
# 此功能将一些所需的属性设置为知识库单例
_setKnowledgeBaseAttributes()
# 将命令行选项与配置文件和默认选项合并
_mergeOptions(inputOptions, overrideOptions)
当运行到173行时,进入init() 函数中,可以看到会进行一系列设置如:http、threads 等等;
def init():
"""
Set attributes into both configuration and knowledge base singletons
based upon command line and configuration file options.
"""
_useWizardInterface()
setVerbosity()
_saveConfig()
_setRequestFromFile()
_cleanupOptions()
_cleanupEnvironment()
_purge()
_checkDependencies()
_createHomeDirectories()
_createTemporaryDirectory()
_basicOptionValidation()
_setProxyList()
_setTorProxySettings()
_setDNSServer()
_adjustLoggingFormatter()
_setMultipleTargets()
_listTamperingFunctions()
_setTamperingFunctions()
_setPreprocessFunctions()
_setPostprocessFunctions()
_setTrafficOutputFP()
_setupHTTPCollector()
_setHttpChunked()
_checkWebSocket()
parseTargetDirect()
if any((conf.url, conf.logFile, conf.bulkFile, conf.requestFile, conf.googleDork, conf.stdinPipe)):
_setHostname()
_setHTTPTimeout()
_setHTTPExtraHeaders()
_setHTTPCookies()
_setHTTPReferer()
_setHTTPHost()
_setHTTPUserAgent()
_setHTTPAuthentication()
_setHTTPHandlers()
_setDNSCache()
_setSocketPreConnect()
_setSafeVisit()
_doSearch()
_setStdinPipeTargets()
_setBulkMultipleTargets()
_checkTor()
_setCrawler()
_findPageForms()
_setDBMS()
_setTechnique()
_setThreads()
_setOS()
_setWriteFile()
_setMetasploit()
_setDBMSAuthentication()
loadBoundaries()
loadPayloads()
_setPrefixSuffix()
update()
_loadQueries()
我们会发现http请求头中 sqlmap 默认发送的 User-Agent 是这样的:
User-Agent: sqlmap/1.4.12#stable (http://sqlmap.org)
所以为了避免被 waf 或者日志里面记录,我们一般可以添加一个 --random-agent
参数在后面:
之后的 User-Agent 会变成这类的:
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16
接下来会进入 ./lib/core/decorators.py
的 stackedmethod() 函数,根据注释,该函数是用来堆栈对齐的回退函数(不太理解该函数)。看到 result 关键字直接步入,然后会执行到start() 函数:
start() 函数对URL稳定性以及所有GET,POST,Cookie和User-Agent参数进行检查,以检查它们是否动态以及是否受到SQL注入的影响
经过一系列的信息获取:Method、paramKey、Headers 等,来到了 437 行进行连接等检查:
我们跟进checkConnection() 函数,会来到 ./controller/checks.py
,先检查 hostname 是否是 ip 形式(xxx.xxx.xxx.xxx),之后检查有没有设置代理,然后输出 log 信息:尝试连接目标 url
后面开始进行 request 请求,跟进 Request 函数,来到 ./request/connect.py
,通过注释可以得知 queryPage 函数是用来获取目标 url 页面内容:
直到调用 Connect.getPage
发起请求开始获取页面内容:
进入 getPage() 函数,经过一系列的赋值:url、get 类型参数、cookie 等:
然后调用 urllib.request.urlopent 发起请求:
获取响应正文信息:
关闭连接:
最后 getPage 函数会 return 出响应正文、响应头以及响应状态码,继续运行回到 queryPage 函数,经过一系列处理 queryPage 函数将响应正文、响应头以及响应状态码也 return 出去:
之后会到 ./lib/core/decorators.py
,会将获取到的 result 返回:
最后回到 checks.py,返回 True,这时候 SQLMap 已经获知目标站点可连接:
2. WAF 判断
2.1 WAF 检测
在 449 行进行 waf 检测:
跟进 checkWaf 函数,又会来到 stackedmethod 函数,直到在 result 进行步入,会来到 checkWaf 函数。根据注释可以得知 sqlmap 的 waf 检测能力来源 nmap 的 http-waf-detect 脚本:
首先将几种攻击类型的 payload(SQL 注入、目录遍历、XSS 等)拼接到已有参数发起请求:
如果直接连接错误,可以判断存在 WAF;若可正常连接,判断不存在 WAF。
2.2 WAF 识别
继续执行到了 identifyWaf 函数,但由于并未设置检测 waf 会被判断跳过。可以按住 command 点击 identifyWaf 函数跟进查看原理;
大概原理是调用 waf 文件夹下脚本进行检测 —> 得到结果;
脚本脚本大概逻辑为:发起请求 —> 获取响应正文、响应头、响应码 —> 根据规则判断 —> 返回结果。
3. 稳定性检测
跟进checkStability() 函数,通过注释发现该函数是用来进行稳定性检测:
此函数检查URL内容是否稳定,两次请求同一页面,每次请求中的延迟很小,以假定它是稳定的;如果请求同一页面时页面的内容不同,则动态性可能取决于其他参数。
4. 参数动态检测
经过一系列赋值、判断,运行至 checkDynParam 函数:
此函数检查URL参数是否为动态,如果是动态的,则页面的内容会有所不同,否则动态性可能取决于另一个参数。
5. 注入检测
运行至 580 行,终于来到关键的注入检测:
跟进 heuristicCheckSqlInjection 函数,在 1023 行进行随机字符串获取,随机字符串长度为 10,并且该随机字符串需满足单引号或者双引号出现次数为 1:
接下来将随机字符串拼接成 payload,发起请求:
1075 行调用 parseFilePaths 函数检测响应正文中是否包含绝对路径:
1076 行检测上一个响应是否有数据库错误信息,这时候的上个请求 payload 是包含单双引号的,通过这种方式可以极快的判断是否存在注入:
当没有数据库的报错信息,还需要继续运行;在 1132 行会生成两个随机变量,长度为 6。接下来生成带 <’ "> 的 payload,该 payload 为第一个随机字符串加上 <’ "> 加上第二个随机字符串。
1088 行出现 agent.payload 函数,跟进该函数 ./lib/core/agent.py
,根据注释得知该函数将受影响的参数替换为要请求的SQL注入语句:
然后调用 cleanupPayload 函数,根据函数名猜测该函数主要是用来进行 payload 清理;最终返回经过处理之后的 payload;之后使用处理之后的 payload 发起请求,最后返回 kb.heuristicTest:
继续运行回到 start 函数,591 行调用 checkSqlInjection 开始进行注入检测:
跟进 checkSqlInjection 函数,调用 InjectionDict 函数设置注入字典,之后对参数值类型进行检查:
134 行调用 getSortedInjectionTests 函数获取待注入类型及其 payload 等信息:
141 行会将 tests 数据取出来,直至取完才能跳出 140 行的 while 循环:
之后对 payload 进行处理,直至 506、527 行调用 Request.queryPage 请求。这时候的 payload 包含 AND 关键字:
之后对结果进行判断,没有满足条件的判断都直接 pass 掉,再开始重新构造 payload 发起请求,直至 payload 为 boolen 类型注入,会进入判断设置 injectable = True:
拆分一下这里的判断逻辑:
- falsePage 与 truePage 是否相等,falsePage 使用的 payload 为 cmpPayload、TruePage 使用的 payload 为 reqPayload。假设得到结果为 A,A 为布尔类型;
- 获取 not kb.nullConnection 结果,假设得到结果为 B,B 为布尔类型;
- 判断 not (A and B),假设得到结果为 C,C 为布尔类型;
- 判断 trueResult and C,假设得到结果为 D,只有 trueResult、C 同为 True。D 才能为 True,满足条件判断;
- 正常情况下 B 为 True,这时候只有 falsePage 不等于 truePage,才能满足条件。
之后对该注入信息进行赋值存储 injection 变量中。由于这时候 injectable 为 True,所以会跳出 372 行的 for 循环:
- 总结
SQLMap 整个运行机制:
-
获取 url、thread、headers 等信息存储至变量中;
-
网站存活性检测;
-
WAF 检测 & WAF 类型识别;
-
稳定性检测;
-
注入检测。