sqlmap如何判断数据库类型

前言

前面发了一个讨论贴,讨论如何判断数据库的类型,再看看sqlmap如何检测数据库类型的。

分析

首先是pycharm打开sqlmap所在的目录,配置好拦截器,配置好调试环境,然后通过关键字it looks like the back-end DBMS is进行定位sqlmap源码,来到sqlmap-master\lib\controller\checks.py 154行

sqlmap是通过Format.getErrorParsedDBMSes()、kb.heuristicDbms、injection.dbms
三个依次获取数据库类型,如果前面为空,则从下一个地方获取类型。

根据getErrorParsedDBMSes判断

最开始的是从错误信息中获取到数据库类型。来跟踪下getErrorParsedDBMSes函数,来到\sqlmap-master\lib\core\common.py 251行

在如上图地方下断点后(一般在有期待返回的结果处下断点,可以少看很多非重点部分),可以看到上一层调用的是heuristicCheckSqlInjection函数。这里是sqlmap的启发式检测sql注入的部分。

1
2
3
4
5
elif result:
infoMsg += "be injectable"
if Backend.getErrorParsedDBMSes():
infoMsg += " (possible DBMS: '%s')" % Format.getErrorParsedDBMSes()
logger.info(infoMsg)

并没有得出他是如何检测出来的,那找下赋值语句,并在此处下断点,并通过栈找下发起http请求,找出payload。

发起请求的页面

1
page, _, _ = Request.queryPage(payload, place, content=True, raise404=False)

请求payload为'id=2,).,()')."',可以看到此payload包含各种符号,从而导致语句报错,获取到数据库类型。

看看使用判断错误的正则在哪里。

sqlmap-master\xml\errors.xml文件中。

根据heuristicDbms判断

再找赋值语句,在下面这段代码中,首先会判断是不是boolean型payload,才会进入检测

进入到heuristicCheckDbms函数中,进行下断点。

这里payload都这样的(SELECT 'OoNG')='OoNG'

前面有一句Backend.forceDbms(dbms),sqlmap会根据库类型自行改变sql语句。那看看sqlmap是怎么对这条语句进行改变,从而进行判断的。这里进行抓包了,从而整理出三个主流的数据库的判断(如果想了解更多的,可以自行去抓包),这里sqlserver和oracle使用字符串连接的语法进行判断,而mysql直接使用hex进行判断。

1
2
3
4
5
6
7
8
sqlserver
AND (SELECT CHAR(108)+CHAR(89)+CHAR(108)+CHAR(76))=CHAR(108)+CHAR(89)+CHAR(108)+CHAR(76)
mysql
AND (SELECT 0x6b6c4246)=0x6b6c4246
oracle
AND (SELECT CHR(117)||CHR(87)||CHR(120)||CHR(114) FROM DUAL)=CHR(117)||CHR(87)||CHR(120)||CHR(114)

根据injection.dbms判断

还是直接找赋值语句,来到sqlmap-master\lib\controller\checks.py 724行

根据上图的赋值语句,发现找不到test.details 的赋值语句,那直接找test

test = tests.pop(0),而tests = getSortedInjectionTests()

通过下断点,观察变量,这些test就是注入的payload,那这些payload从哪里来的,搜索conf.tests,来到sqlmap-master\lib\parse\payloads.py 76行,继续往上溯parseXmlNode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Filenames of payloads xml files (in order of loading)
PAYLOAD_XML_FILES = ("boolean_blind.xml", "error_based.xml", "inline_query.xml", "stacked_queries.xml", "time_blind.xml", "union_query.xml")
.....
.....
def loadPayloads():
for payloadFile in PAYLOAD_XML_FILES:
payloadFilePath = os.path.join(paths.SQLMAP_XML_PAYLOADS_PATH, payloadFile)
try:
doc = et.parse(payloadFilePath)
except Exception, ex:
errMsg = "something appears to be wrong with "
errMsg += "the file '%s' ('%s'). Please make " % (payloadFilePath, getSafeExString(ex))
errMsg += "sure that you haven't made any changes to it"
raise SqlmapInstallationException(errMsg)
root = doc.getroot()
parseXmlNode(root)

找到payload来源于sqlmap-master\xml\payloads的xml文件中。

这里是根据使用的payload判断数据库,如果使用的是mysql的sleep的payload,则判断数据库为mysql。

kb与conf

sqlmap中kb和conf出现的频率很高,如果了解下这两个,分析起来比较好一些。他们在sqlmap-master\lib\core\data.py中定义的。

1
2
3
4
5
6
# object to share within function and classes command
# line options and settings
conf = AttribDict()
# object to share within function and classes results
kb = AttribDict()

在这里仅仅将conf、kb定义成字典。再找赋值语句找到sqlmap-master\lib\core\option.py

这里通过变量名、前面的了解以及注释,可以推测conf便向于存储着请求的一些参数和注入payload,kb偏向于存储着解析返回包与注入的一些参数或者结果。

总结

sqlmap通过三种手段进行判断:
1、通过报错信息获
2、通过字符串拼接或者表现形式
3、通过所属数据库类型的payload