vlambda博客
学习文章列表

SQL注入-Duplicate entry注入报错及原理




本文作者:无名安全团队-usename

SQL注入-Duplicate entry注入报错及原理

现象

如下图,通过duplicate entry报错语句结合数据库函数暴露信息。

SQL注入-Duplicate entry注入报错及原理

image-20211116154728237

原理

相关函数介绍:

1.concat(str1,str2,...):返回结果为连接阐述产生的字符串。如果有任一参数值为null,则返回null

SQL注入-Duplicate entry注入报错及原理

image-20211116155404947

2.floor(n),n为实数:对n向下取整,并返回

SQL注入-Duplicate entry注入报错及原理

image-20211116155629138

3.rand():产生随机数的函数,值为(0,1)之间的随机数。传入一个固定的随机数种子后,可以形成固定发伪随机序列。如下图,直接使用rand()时,每次产生的数都不同,但是当传入随机数种子后,每次产生 的值都是一样的,如rand(0)

SQL注入-Duplicate entry注入报错及原理

image-20211116155937101

所以当rand()函数具有相同的随机数种子后,产生的随机数是可以预知的。

SQL注入-Duplicate entry注入报错及原理

image-20211116160406363

3.函数结合

floor(rand(0)*2):对伪随机数rand(0)的结果乘以2后在向下取整,每次结构都是011011

SQL注入-Duplicate entry注入报错及原理

image-20211116160641610

group by函数:对数据进行分组,值相同的为一组

SQL注入-Duplicate entry注入报错及原理

image-20211116160900462

count()函数:统计表中记录行数,返回匹配条件的行数

SQL注入-Duplicate entry注入报错及原理

image-20211116161216844

4.报错原理

select floor(rand(0)*2) as a,count(*) as a from testb group by (a);

SQL注入-Duplicate entry注入报错及原理

image-20211116161859252

floor(rand(0)*2)的值为011011,经过group by 之后再count统计,理论结果应该是2个0,4个1,但是此处却报错了

关键就是理解group by函数的工作原理

group by(key)在分组时会循环读取每一行,将结果保存在临时表中,每读取一行的key是,如果key存在于临时表中,则更新临时表中的数据(更新数据是,不在计算rand()值);如果key不在临时表中,在临时表中插入key所在行的数据(插入数据时,会重新计算rand()值)

对于语句:select floor(rand(0)*2) as a,count(*) as a from testb group by (a);

执行结果会产生011011这个序列,group by时,建立空虚拟表,然后总sql语句执行结果序列011011读取并插入数据库

key count(*)


1.虚拟表写入第一条记录,执行floor(rand(0)*2),发现结果为0【此时为第一次计算】

操作 key floor(rand(0)*2) count(*)
取第一条记录
0

2.查询虚拟表,发现0值不存在,则插入新的的键值,插入时重新计算floor(rand(0)*2),此时floor(rand(0)*2)=1,插入虚拟表,第一条记录插入完成,结果为1.

操作 key floor(rand(0)*2) count(*)
取第一条记录
0
插入记录 1 1 1

3.虚拟表写入第二条记录,再次计算floor(rand(0)*2),发现结果为1【此时为第三次计算】。此时发现虚拟表中存在key=1,不会进行第四次floor(rand(0)*2)计算,只需在count(*)加1,第二条记录查询完毕。

操作 key floor(rand(0)*2) count(*)
取第一条记录
0
插入记录 1 1 1
取第二条记录,不用插入 1 1 2

4.虚拟表写入第三条记录,再次计算  floor(rand(0)*2),结果为0【第4次计算】。查询虚拟表,发现没有key为0的数据记录,则插入该数据。虚拟表插入数据时,再次计算  floor(rand(0)*2)=1【此时为第五次计算】。但是,key=1这个主键已经存在于虚拟表中,而计算的需要插入的key也为1.所以产生了主键冲突错误,即:duplicate entry的报错,且报错的值为主键的值==floor(rand(0)*2)=1【第五次计算值】

操作 key floor(rand(0)*2) count(*)
取第一条记录
0
插入记录 1 1
取第二条记录,不用插入 1 1 2
取第三条记录
0
插入记录 1??? 1

总结:

通过上述分析,虚拟表在写入第三条记录时,产生报错,此时floor(rand(0)*2)一共计算了5次。所以至少需要3条数据才会产生报错。

SQL注入-Duplicate entry注入报错及原理

image-20211116165732377

另外,floor(rand()*2)产生的序列是不可测的,可能会发生正常无报错的情况。最重要的是,前面几条记录查询后不能让虚拟表产生主键冲突,那之后也不会产生报错。

SQL注入-Duplicate entry注入报错及原理

image-20211116165922861

应用

1.获取数据版本,用户名:

Select count(*),concat(version(),floor(rand()*2),user()) as a from users group by a;

SQL注入-Duplicate entry注入报错及原理

image-20211116170136146

2.所有库名:

select count(*),concat((SELECT schema_name FROM information_schema.schemata limit 0,1),floor(rand(0)*2)) as x_col from information_schema.tables group by(x_col);

image-20211116180835650

3.当前数据库表名等等

select count(*),concat((SELECT table_name FROM information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2)) as x_col from information_schema.tables group

image-20211116180804806