本篇文章给大家分享的是有关借助Burpsuite的Access数据库手工SQL注入是怎样的,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。
环境介绍
目标系统是之前在网上偶然下载的一个CMS系统,在本地装了一个 Windows Server 的虚拟机,开启 IIS。因为是Access数据库,所以不需要安装相关的数据库服务,再其根目录的/data
文件夹下有个data.mdb
文件,即为该数据库文件。
发现注入点
在测试环境里看了一下站点的情况,发现这个CMS在读取新闻内容的时候,URL为http://172.22.10.239/info.asp?id=240
的形式。顺手在id
后面加了个单引号,结果竟然报了500的错误!
进一步进行确认,考虑到这里的id
应该是数据库中的行号,猜想一下相关的查询语句可能的构成应该为:
SELECT {col_name} FROM {table_name} WHERE `id` = {id}
查询语句里面的id
大概率是通过拼接的方式写进去的。为了证实这个猜想,构造一个payload:
?id=240+and+1=1+
+
号在URL中是等同于空格的,为了避免问题空格就用+
代替。
这时候发现依然是500,难道判断错了?还是后面还有别的什么语句吗?不甘心的又尝试了一下or
进行拼接:
?id=240+or+1=1+
这下可以正常显示出页面了。那基本就能确定此处存在注入点,而且大概率是and
字符被替换了。
问题分析
既然发现了注入点,就可以尝试注入。正常的手段是去试过滤规则,但是因为目标是一个CMS,我们手里有后台的源码,因此直接开始对相关页面的源码进行分析,看看它到底用了什么规则去拦截我们的输入。
先打开info.asp
文件,找到处理id
参数的地方。在开头的第 4 行就是一个赤裸裸的 SQL 拼接,语句与我们猜测的完全一致:
那这里的rqs()
又是啥?在library.asp
文件中找到了这个函数的定义:
str_safe函数定义:
看到这里,其实一切规则就都明白了,我们输入的 {空格}and
是在过滤列表中的。那么下一步就是如何绕过并且进行注入了。
尝试注入
ACCESS 数据库与 Mysql 数据库注入的区别主要体现在 ACCESS 是没有 information_schema
这种“总表”,也就是说数据表的名称是无法通过注入的方法读取到,因此需要去猜解。
绕过过滤
在猜解之前需要先绕过过滤。因为有了看到源码的便利,知道了过滤的原理,CMS替换的字符都是带空格的,如{空格}and
, select{空格}
这种,那需要找到绕过空格的方法。
首先想到的是用大小写绕过,比如AnD
这样,但是发现Replace
函数的参数最后是1, -1, 1
。这三个参数分别表示的替换字符的起始、终止和检查类型。检查类型默认为0,设置为1的时候是大小写不敏感的,因此大小写绕过便没有作用了。
那么换个思路,尝试用一些特殊字符来代替空格。存在一些除了%20
、+
以外的字符也可以被 ACCESS 认作空格的作用。这时需要使用 Burpsuite 的 Intruder 工具来进行尝试。
在 Position 界面把要替换的字符,当然这里根据源码里面的规则,将空格字符替换掉,使用 URL 转义的方式填充 %xx
,将除了 ‘%’的部分进行标记。Intruder工具中的 Attack type
选择 Battering ram,这样所有的标记处都会同步的进行变化:
在 Payload 的部分,类型type
选择 Brute forcer,即暴力破解,字符集填上 HEX 的字符集,即 0~9,A~F,最大和最小位数都是 2 位,这样就能遍历 0x00 ~ 0xFF 的全部字符了。
瞬间跑完结果,将结果按照 Response 的状态 Status
排序,是 200 的那几条就是返回了正确页面的。此时就能 初步 得到可以成功跑出结果的字符集。
框中的是初步筛选的结果。这里能够执行成功,不代表成功代替了空格,有可能是引起了其他转义(比如截断等),所以还要将筛选出来的字符用 id=240%{xx}and%{xx}1=2
再跑一次确认一下。因为数量不多,所以用 Simple list 模式将这些 Payload 再做一次测试:
这次的结果中,状态为 500 的返回值说明这个字符是成功的解析成空格的(因为后面注入的是and 1=2
,预期返回的是false
)。从 200 的结果也可以看出,%00
,%16
这两个字符可以用作截断,即 %16
后面的字符不会被当做 SQL 语句进行解析。
所以目前可以确定,当前可用的替代空格的字符为 %09
, %0A
, %0D
。
猜解表名
因为知道了过滤规则,并找到了可替代的字符,就可以尝试猜解表名了。
ACCESS 没有记录数据表名称的系统表,所以不能像 Mysql 那样直接读取,唯一的方法就是暴力猜解表名。
首先构建Payload。在上一步的基础上,将 AND
关键字后面的条件换成尝试表名是否存在的语句即可。这里使用 exists
关键字来完成这个任务:
EXISTS(SELECT NULL FROM `{表名}`)
如果表名不存在,那么这个查询会报错,返回 500;若存在表名,则EXISTS
函数会返回 True,自然页面也会返回 200。
关于表名的猜测,网上有一些类似于 Top 100 的列表可以下载,或者盲猜。一般系统都会有包含 admin 这个名称的表,无非是前面加上前缀,比如国内的CMS会喜欢加上CMS的缩写,或者如 “t_admin” 这种一个字母的形式。这样可以根据目标的特点去构建猜测的列表,用 Intruder 工具将表名列表导入 Simple list中进行暴力破解。
这里这个CMS嘛,因为本地有源码,就开了个挂,直接看到了它的表名,比如管理员表叫做CMS_ADMIN
。
进行注入
现在万事具备,只欠注入了。这里尝试使用 UNION
关键字来把想要的数据给拿出来。使用 UNION
关键字的时候需要知道原查询的字段数,否则会报列数不匹配的问题,自然返回的就是500。预期构建出的完整 SQL 查询如下:
SELECT * FROM `cms_info` WHERE id = 1 UNION SELECT 1,1,1, ... ,1 FROM cms_info
现在需要知道 UNION
中的 1 的个数需要多少个。还是用 Intruder 来尝试,先构建出一条初始的payload: id=1%0Dunion%0Dselect%0D1%0Dfrom%0Dcms_info
,使用%0D
作为空格的替代。插入标记之后的样子如下:
此处 Payload type 选择 Character blocks,Min length设置为2,就是 ",1"的长度。我们想尝试 1~50列,Max length 就设置为 50 * 2 = 100 即可:
将结果按照 Status
排序,200的结果序号是 34,那么说明当前这个新闻页面查询的表的结果一共 35 列(因为初始的时候已经有了 UNION SELECT 1 FROM...
,因此这里列数要根据序号 +1)
但是虽然这里是 200,但是页面并没有返回正常的数据,使用 Repeter 发送这个数据,发现是要跳转到 login.asp 页面:
那么说明返回的字段中是有控制页面显示的功能。各个字段分别的功能需要通过修改字段的值来判断,此处大体就是 0, 1, NULL 三种不同的值排列组合,具体分析方法不再赘述。最终得到注入的结果,比如读到管理员账号密码:
总结分析
这个注入点因为做了替换,将一些主要的 SQL 关键字进行了转义,导致使用 SQLMap 无法直接跑出数据,因此使用手工注入的方式查看。其实也可以通过在 SQLMap 中引入脚本的方式自动替换来达到目的,将空格全部替换成%9D
即可自动化跑出内容(没有试过,但是原理上可行)。
对于 ACCESS 数据库,对于表名、列名都需要盲猜,其实注入难度会很大,但是对于 CMS 系统来说,表名和字段名是公开的,一般用户在使用的时候又不会特别去进行修改,一旦出现注入点会有很大的隐患。
对于防止 SQL 注入,像这种替换显然是有问题的,关键字 + 空格的识别还是有很多方法可以进行绕过,如果担心匹配太严格影响业务,也可以从允许的变量类型、长度等方面进行局部限制,来消减 SQLI 的隐患。
以上就是借助Burpsuite的Access数据库手工SQL注入是怎样的,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注亿速云行业资讯频道。
原创文章,作者:506227337,如若转载,请注明出处:https://blog.ytso.com/tech/safety/225982.html