SQLMap原理分析(一)

记得好久以前看过SQLMap的原理分析,但是那时候仅仅只是看过并没有自己去研究。因此,这次想深入研究一下SQLMap的原理。大概会从网络请求、运行流程、源码这些角度进行分析。

前期准备

测试环境

先准备几个不同数据库的测试环境:MySQL、Oracle、SQLServer等。这里偷懒就直接用AWVS提供的环境:http://testphp.vulnweb.com、http://testasp.vulnweb.com。

SQLMap

SQLMap可以在官方站点下载也可以通过Git命令从GitHub下载。git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev

如果已经有SQLMap,可以更新到最新版本。这里我用的是1.3.4.51#dev版本

1
2
python sqlmap.py --update
python sqlmap.py --version

请求分析

通过对请求分析可以很直观看到SQLMap从开始到结束中间一共进行过什么操作。分析思路为找到SQLMap关键的几个请求包进行分析,得出SQLMap大概的一个操作流程以及判断逻辑。Ps:下文中包的数字等信息并不固定。

MySQL

在testphp站点随便找一个注入点,可以发现登录口存在注入,用BurpSuite(代理端口8080)将请求保存成sql.txt,然后使用sqlmap进行注入。

python sqlmap.py -r sql.txt -p uname --proxy http://127.0.0.1:8080

正常情况下这时候已经可以在BurpSuite的proxy-history里面看到sqlmap发的请求了。

首先会不直接按照sql.txt中的请求包发起一次请求根据响应进行下一步操作,由于该处登录口登录失败会进行302跳转。因此,SQLMap会有一个是否跟进302的提示。

302跳转.png

接下来可以看到SQLMap猜测该处为MySQL数据库,大概为第五、六个包。

  1. 按照sql.txt发起请求;
  2. 在url后面加参数发起请求;
  3. 将POST请求变成GET请求;
  4. 不改动再发起一次请求;
  5. 增加特殊字符发起请求:‘、"。

根据服务器回显报错得出可能为MySQL数据库。

MySQL_Error.png

接下来会猜测注入类型型,大概在第一百四十六个包会得出注入点uname为布尔盲注,根据请求可以看到payload。

1
uname=est' AND (SELECT 2*(IF((SELECT * FROM (SELECT CONCAT(0x71627a7671,(SELECT (ELT(4376=4376,1))),0x71766b6271,0x78))s), 8446744073709551610, 8446744073709551610)))-- GUJT

判断依据为该请求服务器可以正常响应。

接下来会对数据库版本以及函数进行猜测,大概在二百二十七个包会得出可以使用union以及共有8个字段。

union.png

最后对进行一次验证,并得出结论。

result.png

SQLServer

随便找一个注入点:http://testasp.vulnweb.com/showforum.asp?id=0,将流量代理到BurpSuite。

SQLMap第一次认为该处不存在注入,可以看到是输入特殊的字符根据响应进行判断:‘、"。一共发起两次特殊字符请求进行注入点判断,服务器响应为500,并且响应包里面没有带数据库报错等信息。因此,SQLMap猜测该处并不存在注入。

SQLServer_error.png

但是后来SQLMap发现该处为布尔类型的盲注,根据时间来看是11:59:59时判断的。根据BurpSuite的时间戳找到这个时间点的请求包得知payload:0 and 9756=9756,并且服务器的响应为200。

and.png

接下来SQLMap判断该数据库类型为SQLServer,根据前后的请求包来看应该是按照不同连接符号得出的不同结论来进行判断。

可以看到一共用了三种连接符号,在使用||,服务器返回为200响应码。

  1. ||
  2. &

||code=200.png

接下来会开始猜测注入类型,会得出该注入点是SQLServer可注入,并且是什么类型注入。

注入类型.png

接着通过order by来猜测字段长度,可得出长度为2。

order by 2.png

最终会输出结果。

sqlserver-result.png

Oracle

待测试。

总结

根据上面的测试可以得知SQLMap大致工作流程:数据库类型猜测、注入类型猜测、数据库版本猜测(MySQL不同版本会影响后续payload选择)、字段长度猜测、结论输出等。

  1. 数据库类型猜测使用特殊字符来完成:单引号、双引号、连接符等;
  2. 注入类型猜测通过函数来完成:char、union、concat、select等;
  3. 长度猜测用的是order by。

这次测试注入点都是简单的注入点,因此看起来很类似。或许在复杂的注入点中间用的函数或者特殊字符不同,但是流程上应该是保持不变的。