SQL–报错注入(join无列名注入)_join注入-CSDN博客
主键重复报错
floor()
向下取整,类似于⌊x⌋
rand(0)和 rand()
只要括号里输入的数字是一样的,rand(数字)的结果就会一直一样。
rang()生成一个位于 0 到 1 之间的数字。
一条常见的查询语句
数据库内部“按行”扫描原数据表,发现一个新的值就添加进去,发现重复的就计数+1 直到全部读完。
如果我们有以下表:
id | username |
---|---|
1 | Alice |
2 | Bob |
3 | Alice |
4 | Carol |
5 | Alice |
6 | Bob |
那么我们执行这条语句:
1 | SELECT username, COUNT(*) FROM users GROUP BY username; |
结果是:
username | count(*) |
---|---|
Alice | 3 |
Bob | 2 |
Carol | 1 |
那么,他的实现过程是如何的呢?可以联想到group by子句的执行流程,最初时,username-count()这个数据表是空的,通过一行一行读原数据表中的user字段,如果读到的user在user-count() 数据表中不存在,就将它插入,并且将对应的count() 赋为1,如果存在,就将其对应的count() +1,直至扫完整个数据表。
下面就是一个很有意思的机制,当我们执行这条语句:
1 | select count(*) from sqli group by floor(rand(0)*2); |
每一行都会计算floor(rand(0)*2),结果是 0 或 1,在使用group by的时候,floor(rand(0)*2)会被执行一次,如果虚表不存在记录,插入虚表的时候会再被执行一次。
1.查询前默认会建立空的虚拟表
2.取第一条记录,执行floor(rand(0)*2),发现结果为0(第一次计算),查询虚拟表,发现0的键值不存在,则floor(rand(0)*2)会被再计算一次,结果为1(第二次计算),插入虚表,这时第一条记录查询完毕
3.查询第二条记录,再次计算floor(rand(0)*2),发现结果为1(第三次计算),查询虚表,发现1的键值存在,所以floor(rand(0)2)不会被计算第二次,直接count()加1,第二条记录查询完毕
4.查询第三条记录,再次计算floor(rand(0)*2),发现结果为0(第4次计算),查询虚表,发现键值没有0,则数据库尝试插入一条新的数据,在插入数据时floor(rand(0)*2)被再次计算,作为虚表的主键,其值为1(第5次计算),然而1这个主键已经存在于虚拟表中,而新计算的值也为1(主键键值必须唯一),所以插入的时候就直接报错了
5.整个查询过程floor(rand(0)2)被计算了5次,查询原数据表3次,所以这就是为什么数据表中需要3条数据,使用该语句才会报错的原因。
如果有一个序列开头时0,1,0或者1,0,1,则无论如何都不会报错了,因为虚表开头两个主键会分别是0和1,后面的就直接count()加1了.
这一段如果看的很乱可以丢给 GPT 帮忙讲一下。
步骤1:查询开始,虚拟表是空的。
步骤2:读第一行数据
- 第一次执行
FLOOR(RAND(0)*2)
,得到 0 - 查虚拟表,发现没有键 0,于是要插入它
- 但是——在真正插入表的时候,MySQL **又执行了一次 **
**FLOOR(RAND(0)*2)**
(这是它的实现机制)- 第二次计算结果变成了 1
- 所以最终插入的是键 1
- 现在虚表是:
{1: 1}
(表示键为 1 的组,计数为 1)
步骤3:读第二行数据
- 第三次执行
FLOOR(RAND(0)*2)
,得到 1 - 查虚拟表:发现已经有键 1,于是把它的计数 +1
- 虚表变成
{1: 2}
步骤4:读第三行数据
- 第四次执行
FLOOR(RAND(0)*2)
,得到 0 - 查虚拟表,没有键 0,准备插入
- 插入时再次计算
FLOOR(RAND(0)*2)
(第 5 次),结果又是 1 - 但 1 已经存在于表中了 → ❗️违反了主键唯一性 → 触发 报错!
所以至少需要三条数据才能报错,且有几率不会报错。如果有一个序列开头时0,1,0或者1,0,1,则无论如何都不会报错了,因为虚表开头两个主键会分别是0和1,后面的就直接count(*)加1了.
rand()*2 由于是随机的,所以我们用它的时候有可能前两个刚好一个 0,一个 1 之后的记录只会 count(*) +1
,**不会再试图插入新键,**所以不会触发主键冲突,不会报错。
xpath语法错误报错(>mysql5.1.5)
这两个函数是用来 XML 查询和修改的,记住都能报错了。
updatexml()报错
updatexml(XML_document, XPath_string, new_value)
updatexml(XML 文档名称, XPath 格式的字符串, 替换数据)
因为第二个参数要求 Xpath 格式,所以我们传一个不是这个格式的就会报错,大多用十六进制的~
,也就是 0x7e,我们把需要的数据和报错的连起来就会儿一起回显, 也就是CONCAT(0x7e, (SELECT database()), 0x7e)
首尾随便填。
从配枪朱丽叶搬运来的 payload:
1 | select pname,pagefrompersonwherepwd='111'andupdatexml(1,concat(0x7e,(selectdatabase()),0x7e),1); |
@@versions 是MySQL 内置的全局变量,它的作用是:返回当前 MySQL 数据库的版本号。
extractvalue()报错
extractvalue(XML_document, xpath_string)
extractvalue(XML 文档名称, XPath 格式的字符串)
1 | select pname,page from person where pwd = '111' and (extractvalue('hhhhhhh',concat(0x7e,substring(hex((select database())),1,20)))); |
长度限制 32 位,超过可以用
数据溢出报错
双精度溢出报错
Exp函数返回e的幂次方。在MySQL中。当传入的参数>=710会报错。并且会返回报错信息。利用方法如下:
1 | select exp(~(select*from(select user())x)); |
表示按位取反操作,通俗的讲就是能把一个很小的数变成一个很大的数。比如0=18446744073709551615,从而达到溢出的效果。
整型溢出报错
几何函数报错(5.7.17-5.5.48)
mysql有些几何函数,例如geometrycollection(),multipoint(),polygon(),multipolygon(),linestring(),multilinestring(),这些函数对参数要求是形如(1 2,3 3,2 2 1)这样几何数据,如果不满足要求,则会报错。
1 | multipoint((select * from(select * from(select user())a)b)); |
列名重复报错(Mysql 5.0.12-5.0.51)
name_const()
name constant 创建一个带有名字的常量值列。
NAME_CONST(列名, 值)= SELECT 值 AS 列名
当我们执行:
1 | SELECT name_const(version(),1); |
会返回一个列名为 <font style="color:#000000;">abc</font>
,值为 <font style="color:#000000;">123</font>
的一列:
1 | +--------+ |
如果列名重复,MYSQL 会报错。
示例 payload:
1 | select * from (select name_const((select database()),1),name_const((select database()),1))a; |
外面包一层<font style="color:#000000;">select * from</font>
是模拟实际情况,也就是说 <font style="color:#000000;">SELECT * FROM (payload) AS a</font>
这里的 payload 是
1 | SELECT name_const((SELECT database()), 1), |
join()
join具有 连接的作用,即当两个或者两个以上的表有关系时,需要用join来连接这些相关的表,来处理或分析数据:
MySQL中的join以及on条件的用法_join on-CSDN博客
mysql 不允许有两个相同的列名,所以会报错。
1 | mysql> select * from(select * from users a join users b)c; |