freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

渗透测试之SQL注入(四)
2020-10-22 16:12:48

前文写的是boolean注入,今天来给师傅们写写报错注入。

一、什么是报错注入

顾名思义,报错注入就是通过页面爆出的错误信息,构造合适的语句来获取我们想要的数据,本章节讲述的注入,数据库为MySQL。

二、出现报错注入的原因

首先是应用系统未关闭数据库报错函数,对于一些SQL语句的错误,直接回显在了页面上,部分甚至直接泄露数据库名和表名;

其次,必不可少就是后台未对MySQL相应的报错函数进行过滤

三、集中常见的报错注入用到的函数

1.updatexml()

2.floor()

3.extractvalue()

4.exp()

但这里使用最为常见的还是updatexml()函数

四、updatexml()的使用方法

updatexml()的语法为

UPDATEXML (XML_document, XPath_string, new_value);

第一个参数:XML_document是String格式,为XML文档对象的名称

第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。

第三个参数:new_value,String格式,替换查找到的符合条件的数据

如果找不到相应的xpath路径,updatexml函数就会报出错误

concat()函数。此函数用于连接字符串;由于updatexml()函数xpath路径需要连接特殊字符,被连接的特殊字符需要进行16进制编码

concat_ws()函数。语法concat_ws(0x7e,database(),use()),会把查出来的库名和用户通过~连接起来完成报错

下面我门可以进入到sqli-lab的第五关

输入?id=1看看是什么个样子

1602573137_5f855351bed1e451fdea5.png!small

出现了一个You are in.......的字样

那我们在后面再加一个单引号闭合看看出现什么

1602573198_5f85538e1fed1c2eab657.png!small

这里爆出了错误语句,这个时候我们就可以利用我们报错注入来进行注入了

我们可以利用如下的payload

?id=-1'union select count(*),count(*), concat('~',(select database()),'~',floor(rand()*2)) as a from information_schema.tables group by a--+

这里就爆出了数据库名

1602574244_5f8557a443a7ee7369512.png!small

接下来就是表名、字段名等,那么这个payload实现的原理是什么呢。

几个关键函数的说明

rand(0)*2

rand() 可以产生一个在0和1之间的随机数。

可见,每次产生的都不一样。当我们提供一个种子参数 0 后,再次查看:

可以发现,每次产生的值都是一样的。也可以称之为伪随机(产生的数据都是可预知的)。
查看多个数据看一下。( test 是我之前创建的一个拥有9条数据的表)

发现第一条数据与刚才查看的单个数据相符合,其它的数据也完全一样。
为什么要乘以 2 呢?这就要配合 floor 函数来说了。

floor(rand(0)*2)

floor() 返回小于等于该值的最大整数。
之前我们了解到,rand() 是返回 0 到 1 之间的随机数,那么乘 2 后自然是返回 0 到 2 之间的随机数,再配合 floor() 就可以产生确定的两个数了。也就是 0 和 1。

为什么需要这两个数呢?

group by 与 count(*)

group by 主要用来对数据进行分组(相同的分为一组),这里与count() 结合使用。举个例子就一目了然了。

可以观察到,这里对重复性数据进行了整合,然后计数。

重点来了,也就是在这个整合然后计数的过程中,中间发生了什么我们是必须要明白的。
经过网上查询,发现mysql遇到该语句时会建立一个虚拟表。该虚拟表有两个字段,一个是分组的 key,一个是计数值 count(*)。也就对应于上个截图中的 prod_price 和 count(*)。
然后在查询数据的时候,首先查看该虚拟表中是否存在该分组,如果存在那么计数值加1,不存在则新建该分组。

报错分析

rand()的特殊性

select count(*) from test group by floor(rand(0)*2);

而又因为 rand 函数的特殊性(如果使用rand()的话,该值会被计算多次)。
在这里的意思就是,group by 进行分组时,floor(rand(0)*2)执行一次(查看分组是否存在),如果虚拟表中不存在该分组,那么在插入新分组的时候 floor(rand(0)*2)就又计算了一次。(其实在上述 rand(0) 产生多个数据的时候,也能观察出来。只要 rand(0) 被调用,一定会产生新值)。

这样,所有的理论细节就全部明朗了。

报错

还记得我们之前产生的疑问,为什么要用 floor(rand(0)*2产生 0 和 1 这两个数吗?

当 group by 对其进行分组的时候,首先遇到第一个值 0 ,发现 0 不存在,于是需要插入分组,就在这时,floor(rand(0)*2)再次被触发,生成第二个值 1 ,因此最终插入虚拟表的也就是第二个值 1 ;然后遇到第三个值 1 ,因为已经存在分组 1 了,就直接计数加1(这时1的计数变为2);遇到第四个值 0 的时候,发现 0 不存在,于是又需要插入新分组,然后floor(rand(0)*2)又被触发,生成第五个值 1 ,因此这时还是往虚拟表里插入分组 1 ,但是,分组 1 已经存在了!所以报错!

总结

可见,floor(rand(0)*2的作用就是产生预知的数字序列01101,然后再利用 rand()的特殊性和group by的虚拟表,最终引起了报错。




# 渗透测试 # SQL注入
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录