access偏移注入原理

  • 前言:近段时间在学习access偏移注入时,在网上查询了大量的资料,感觉很多资料讲解的十分模糊并且我个人认为有很多不够严谨的地方,于是我便在线下经过大量测试,写出以下文章,如有错误,望指出。
  • 如要转载,请标明出处!!

一、认识偏移注入

  • 偏移注入的适用背景:
    • access数据库与mysql不同,access数据库没有类似于mysql的information_schema这样的系统数据库,所以对于access的表名及其字段名我们只能靠经验进行猜解,而偏移注入就是提供了另外一种思路:
    • 在我们只能猜解出表名,而猜解不出我们所想要的字段名的情况下,直接爆最后的字段数据。
  • 偏移注入的原理(这里只是粗略的概述,详细请看下面):
    • 就是将目标表进行(多级)内连接,通过联合查询和已知目标字段名的微调,将我们想要知道的字段值在已经确定的显示位上暴露出来。
  • 影响偏移注入成功率的因素(当然这些因素都是影响因素,不是决定因素):
    1. 联合查询中显示位的位置
    2. 当前注入点所查询的字段数量
    3. 目标表的字段数量
    4. 我们可以猜解到的目标表的字段名的数量

二、实战测试环境

  • 此次实战测试主要涉及的两张表:product表和admin表
    • product表:该表有22个字段
      01_access偏移注入-product表
    • admin表:该表有6个字段(请谨记这个字段数
      02_access偏移注入-admin表

三、前置知识

  1. exist()函数:用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False。
    03_access偏移注入-exist函数

  2. as关键字:用于起别名,可以为表起别名,也可以为字段起别名(as关键字可省略)
    04_access偏移注入-as关键字

  3. 表1 inner join 表2 on 筛选条件 :该关键字用于将表1与表2做笛卡尔积,然后根据on后面的条件进行筛选。

    • 下图中select语句的意思是:将admin表与自己做笛卡尔积,然后筛选出两者id值相同的记录
      05_access偏移注入-内连接
  4. top n 关键字:作用是使查询结果只显示前n条记录
    06_access偏移注入-top关键字

四、原理讲解

  • 为了方便讲解,我们在这里选择 “实战” 和 “偏移注入的注入原理” 相结合的方式进行讨论。
  • 偏移注入的流程是:
    1. 判断是否存在注入点
    2. 判断当前注入点所查询的字段数量 (请一定谨记以下的简略表述,后面的文章均采用以下简略表述)
      • 为方便之后讲解,我们
      • 把【当前注入点对应表】称作为 【当前表】
      • 把【当前注入点所查询的字段数量】称作为【当前字段数量】
      • 把我们将要进行【联合查询的表】称为【目标表】
      • 使用sql语句帮助理解:select 当前字段数量 from 当前表 union select ... from 目标表
      • 在这里【当前表】->product表;【目标表】->admin表
    3. 猜解目标表的表名
    4. 确定显示位
    5. 确定目标表的字段数量
    6. 开始进行偏移注入,经过不断的“微调”,将我们想要的字段值在显示位处暴露出来。

4.1 判断是否存在注入点

  • payload:
    • ?id=1513 and 1=2 页面显示出错
    • ?id=1513 and 1=1 页面显示正常
    • 说明存在注入点,且为数字型注入
      07_access偏移注入-注入点的判断

4.2 判断注入点所查询的字段数(即:当前字段数量)

  • payload:
    • ?id=1513 order by 22
    • 页面返回正常,说明当前注入点本身所查询的字段数量为22(即:当前字段数量为22)
      08_access偏移注入-判断注入点所查询的字段数

4.3 猜解目标表的表名

  • payload:
    • ?id=1513 and exists(select * from admin)
    • 因为access数据库没有类似于mysql的information_schema这样的系统索引库,所以我们只能根据经验靠猜了,在真实的测试环境中,我们也可以通过社工的方式进行猜解。此次页面返回正常,说明存在access数据库中存在admin表。
      09_access偏移注入-猜解目标表的表名

4.4 确定显示位

  • payload:
    • ?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
    • 在页面的源码中,我们可以看到存在3,9,13,15 四个显示位
      10_access偏移注入-确定显示位

4.5 确定目标表的字段数量

  • payload:
    • ?id=1513 and exists(select * from admin order by 6)
    • 页面返回正常,说明admin有6个字段
      11_access偏移注入-确定目标表的字段数

4.6 开始进行偏移注入

  • 偏移注入的基本公式

    • 联合查询所要补充的字段数 = 当前字段数量 - 目标表的字段数 x N(N=1,2...)【注意:“联合查询所要补充的字段数” 指的是union关键字后面的select查询所需补充的字段数】
    • 在此处即为:联合查询补充字段数 = 当前字段数量(22) - admin表的字段数(6) x N
    • 当N=1时我们称为 “1级偏移注入”,当N=2时我们称为 “2级偏移注入”;当N=3时我们称为 “3级偏移注入”,...
  • 1级偏移注入的payload

    • 根据公式我们可以计算出:联合查询补充字段数 = 22-6x1 = 16
    • ?id=1513 union select top 1 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, * from admin
    • 在这里我们解释一下,为什么1级偏移注入并没有爆出我们想要的字段值呢:
      • 由前面的步骤我们已经得知,已经确定的显示位只有 3,9,13,15 四个,即只有处于第3,9,13,15这四个字段的数据才可以显示出来,
      • 但是我们观察下标发现,在进行1级偏移注入时,admin表的数据实际上是排在了17号字段之后了,当然不会在页面中显示出来。
      • 那么我们怎么样才可以将admin表的数据向前移动,以致可以使其处于第3,9,13,15号字段而显示出来呢?
      • 答案是:我们可以进行2级(多级)偏移注入(即通过admin表的自连接使得sql语句中“ * ”所代表的的字段数增大,那么联合查询中用于充数字段就会减小,这样的话,admin表中的数据自然会向前移动了)
        12_access偏移注入-1级偏移注入
  • 2级偏移注入的payload

    • 根据公式我们可以计算出:联合查询补充字段数 = 22-6x2 = 10
    • ?id=1513 union select 1,2,3,4,5,6,7,8,9,10, * from (admin a inner join admin b on a.id=b.id)
    • 根据页面返回的数据,我们可以看到,在第13号显示位,我们成功的爆出了 密码值:a48e190faf
    • 但这是为什么呢?
      • 通过分析下图中表2我们发现,经过2级偏移注入,我们成功的将admin表的数据向前移动了6个字段,使其原本在17号字段及其之后才显现出的数据,变为了在11号字段及其之后就可回显而出。而此时admin表的password字段和count_time字段恰好处于显示位13和15上,于是就自然而然的暴露了出来。
    • 那又为什么admin表的数据会向前移动6个字段呢?
      • 原因就是,由于admin表进行了一次自连接,使得payload中from关键字后面的表由原有的 “admin表” 变成了:由“先让admin自己做笛卡尔积然后挑选id值相等的记录”组成的表。这样的话,payload中的“ * ”就由原来所代表的 “admin表” 中的6个字段,变为了现在所代表的 “admin自连接表” 的12个字段,又由于union关键字的使用,要求union关键字后面select查询的字段数必须要等于前面select查询的字段数,所以union关键字后面的select中用于充数的字段由原来的22-6=16变为了22-12=10个字段,因此由于充数的字段变少了,那么admin表的数据自然的就可以向前移动了。
      • 请注意:admin表中的数据向前移动的字段数只能是admin表(即目标表)字段数的整数倍(这是由表自连接的特性所决定的)。
        13_access偏移注入-2级偏移注入
    • 在此我们已经爆出了admin表的密码,
    • 此时,其实admin表的admin字段就紧挨在password字段的前方(其实在实战环境中我们是不确定admin字段是在前还是在后的,此处只是为了方便原理的讲解,就直接告诉你了)
    • 那么我们是否仍然可以将数据向前移动而爆出admin字段的值呢?在这里显然是不行的,因为我们只能向前移动admin表的字段数量的整数倍(在这里即是6的整数倍),而此时admin表的admin字段此时所处字段为12号字段,再向前移动6个字段的话,admin字段就处于6号字段处了,仍然没有与显示位的位置发生重合。
  • 到了这里,细心的同学会发现:

    • 之前我们讲的都是如何将admin表中的数据向前移动,那么我们可不可以使得数据向后移动呢?要是可以向后移动的话,紧接着2级偏移,然后让数据向后移动一个字段,不就正好让admin字段处于13号显示位了吗?
    • 恭喜你!你的想法是对的,我们的确可以让admin表的数据向后移动,不过遗憾的是,向后移动的字段数仍然取决于:我们能够猜解出admin表中多少个字段名。若猜解出1个字段名,那么我们就可以让数据向后移动1个字段数,若猜解出2个字段名,那么我们就可以让数据向后移动2个字段数,以此类推。(不过这里所需要猜解的字段名不需要是我们想要查找的字段名,只要是admin表中的字段名均可),原因请继续往后阅读:
  • 微调payload:

    • ?id=1513 union select top 1 1,2,3,4,5,6,7,8,9,10,b.id, * from (admin a inner join admin b on a.id=b.id)
    • 根据页面返回的数据,我们可以看到,在第13号显示位我们成功的爆出了admin字段的第一个值:admin
    • 原因:
      • 我们先观察sql语句,发现union关键字后面的select查询的填充字段多了代码“b.id”,意思是在此输出b表(admin表的别名之一)的id字段值,由于此处已经显式的指出id字段值的输出位置,那么后面的 “ * ” 就会自动的识别,就只输出admin自联表剩下的字段值了,从而使得剩余数据均向后移动了一个字段,让原本在13号字段的admin字段向后移动了1位,到了13号显示位上了。
      • 但请注意:此处的id字段名是我们已经猜解出的
      • 这也就回答了上述所说的:“向后移动的字段数仍然取决于:我们能够猜解出admin表中多少个字段名,不过这里所需要猜解的字段名不需要必须是我们想要查找的字段名,只要是admin表中的字段名均可”。因此,如果我们想让admin数据向后移动2个字段值,那么我们就需要知道除了id字段名外,其他任一字段名即可,然后构造如下payload:?id=1513 union select top 1 1,2,3,4,5,6,7,8,9,10,b.id,b.字段名 * from (admin a inner join admin b on a.id=b.id)
        14_access偏移注入-微调

5. 总结与反思

  • 至此,整个测试已结束,我们成功的爆出了 账号与密码:admin/a48e190faf
  • 接下来我会依次提出几个问题,然后一一进行解答:
    1. 如果我们仍然采用上述环境,那可不可以进行3级偏移和四级偏移呢?
      • 答:3级偏移可以,但是4级偏移不行,因为如果进行4级偏移的话,就会使得偏移注入基本公式:联合查询补充字段数=当前字段数量-目标表的字段数 x 4 ==> 22-6x4=-2<0,即:会造成union关键字之前的select查询字段数的数量 < union关键字之后的字段数量,从而导致查询失败。
      • 3级偏移的payload:?id=1513 union select top 1 1,2,3,4, * from((admin as a inner join admin as b on a.id=b.id) inner join admin as c on a.id=c.id)
    2. access偏移注入是否是真的随机?
      • 通过上述原理的讲解,这个问题也就不攻自破了,显然access注入并不是真正的随机,并不是完全不受我们控制的,在我们获取足够信息的情况下(“目标表”的字段数量,当前字段数量,已知的“目标表字段名"的数量),我们可以在一定范围内完全控制显示位处的数据显示,而之所以说是一定范围内,只是因为 “显示位的位置” 和 “我们可以猜解到的目标表字段名的数量” 这两个因素不是我们可以控制的。
    3. 是否可以只说:“当前表”的字段数越多成功率越大,或“目标表”的字段数越少成功率越大?
      • 显然我们不能这样简单的得出结论,偏移注入是否能够成功,取决于:“显示位位置” 和 “目标字段能够移动到的位置” 是否可以重合,如果可以重合的话,即使“当前表”字段数小一点,“目标表”字段数多一点也是无妨的(但万万不可“当前表”的字段数量 < “目标表”的字段数量)
    4. 是什么决定着“目标表”的数据一次性前移的字段数?是什么决定着“目标表”的数据可以后移的字段数?
      • 前者是由 “目标表的字段数量” 所决定的:目标表中的数据 向前移动的字段数 只能是 目标表中的字段数的整数倍(这是由表自连接的特性所决定的)。
      • 后者是由 “我们可以猜解得到的目标表的字段名数量” 所决定。若猜解出1个字段名,那么我们就可以让数据向后移动1个字段数,若猜解出2个字段名,那么我们就可以让数据向后移动2个字段数,以此类推。(不过这里所需要猜解的字段名不需要必须是我们想要查找的字段名,只要是admin表中的字段名均可)
posted @ 2022-01-16 22:42  浅易深  阅读(2918)  评论(4编辑  收藏  举报