CVE-2016-15026 (published 2023-02-20T11:15Z)

A vulnerability was found in 3breadt dd-plist 1.17 and classified as problematic. Affected by this issue is some unknown functionality. The manipulation leads to xml external entity reference. An attack has to be approached locally. Upgrading to version 1.18 is able to address this issue. The patch is identified as 8c954e8d9f6f6863729e50105a8abf3f87fff74c. It is recommended to upgrade the affected component. VDB-221486 is the identifier assigned to this vulnerability.

CVSS v3 base score: 7.8, HIGH (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-611
cwe_name: Improper Restriction of XML External Entity Reference
description: The product processes an XML document that can contain XML entities with URIs that resolve to documents outside of the intended sphere of control, causing the product to embed incorrect documents into its output.
extended_description: 
            XML documents optionally contain a Document Type Definition (DTD), which, among other features, enables the definition of XML entities. It is possible to define an entity by providing a substitution string in the form of a URI. The XML parser can access the contents of this URI and embed these contents back into the XML document for further processing.
            By submitting an XML file that defines an external entity with a file:// URI, an attacker can cause the processing application to read the contents of a local file. For example, a URI such as "file:///c:/winnt/win.ini" designates (in Windows) the file C:\Winnt\win.ini, or file:///etc/passwd designates the password file in Unix-based systems. Using URIs with other schemes such as http://, the attacker can force the application to make outgoing requests to servers that the attacker cannot reach directly, which can be used to bypass firewall restrictions or hide the source of attacks such as port scanning.
            Once the content of the URI is read, it is fed back into the application that is processing the XML. This application may echo back the data (e.g. in an error message), thereby exposing the file contents.
         
         

Fix information:
repo_url: https://github.com/3breadt/dd-plist
commit_details: repo_url: https://github.com/3breadt/dd-plist
author: David Solin
author_date: 2016-10-04 20:51:43-05:00
msg: 1) Take steps to guard against external XXE attacks (except, note that <!DOCTYPE> cannot be disabled in XML plists).
2) Resolve the actual PLIST DTD from inside the JAR file itself, and prevent resolution of other external XML resources.
3) Make XMLPlistParser.getDocBuilder public
repository: repo_url: https://github.com/3breadt/dd-plist
repo_name: 3breadt/dd-plist
description: A java library providing support for ASCII, XML and binary property lists.
repo_language: Java
owner: 3breadt
file_changes: filename: build.xml
change_type: ModificationType.MODIFY
diff: @@ -34,7 +34,8 @@
 
   <target name="jar" depends="compile">
     <jar destfile="${dist}/${jar}">
-     <fileset dir="${build}/classes"/>
+      <fileset dir="${build}/classes"/>
+      <fileset dir="${source}" includes="**/*.dtd"/>
     </jar>
   </target>
 

programming_language: Shell
filename: PropertyList-1.0.dtd
change_type: ModificationType.ADD
diff: @@ -0,0 +1,19 @@
+<!ENTITY % plistObject "(array | data | date | dict | real | integer | string | true | false )" >
+<!ELEMENT plist %plistObject;>
+<!ATTLIST plist version CDATA "1.0" >
+
+<!-- Collections -->
+<!ELEMENT array (%plistObject;)*>
+<!ELEMENT dict (key, %plistObject;)*>
+<!ELEMENT key (#PCDATA)>
+
+<!--- Primitive types -->
+<!ELEMENT string (#PCDATA)>
+<!ELEMENT data (#PCDATA)> <!-- Contents interpreted as Base-64 encoded -->
+<!ELEMENT date (#PCDATA)> <!-- Contents should conform to a subset of ISO 8601 (in particular, YYYY '-' MM '-' DD 'T' HH ':' MM ':' SS 'Z'.  Smaller units may be omitted with a loss of precision) -->
+
+<!-- Numerical primitives -->
+<!ELEMENT true EMPTY>  <!-- Boolean constant true -->
+<!ELEMENT false EMPTY> <!-- Boolean constant false -->
+<!ELEMENT real (#PCDATA)> <!-- Contents should represent a floating point number matching ("+" | "-")? d+ ("."d*)? ("E" ("+" | "-") d+)? where d is a digit 0-9.  -->
+<!ELEMENT integer (#PCDATA)> <!-- Contents should represent a (possibly signed) integer number in base 10 -->

programming_language: PHP
filename: XMLPropertyListParser.java
change_type: ModificationType.MODIFY
diff: @@ -32,6 +32,7 @@ import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.text.ParseException;
@@ -44,24 +45,25 @@ import java.util.List;
  * @author Daniel Dreibrodt
  */
 public class XMLPropertyListParser {
-
-    private static DocumentBuilderFactory docBuilderFactory = null;
-
-    /**
-     * Instantiation is prohibited by outside classes.
-     */
-    protected XMLPropertyListParser() {
-        /** empty **/
-    }
-
-    /**
-     * Initialize the document builder factory so that it can be reused and does not need to
-     * be reinitialized for each parse action.
-     */
-    private static synchronized void initDocBuilderFactory() {
-        docBuilderFactory = DocumentBuilderFactory.newInstance();
-        docBuilderFactory.setIgnoringComments(true);
-        docBuilderFactory.setCoalescing(true);
+    private static final DocumentBuilderFactory FACTORY = DocumentBuilderFactory.newInstance();
+    static {
+        try {
+            FACTORY.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+            Float v1_7 = new Float("1.7");
+            Float javaVersion = new Float(System.getProperty("java.specification.version"));
+            if (javaVersion.compareTo(v1_7) >= 0) {
+                FACTORY.setFeature("http://xml.org/sax/features/external-general-entities", false);
+                FACTORY.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+            }
+            FACTORY.setXIncludeAware(false);
+            FACTORY.setExpandEntityReferences(false);
+            FACTORY.setNamespaceAware(false);
+            FACTORY.setIgnoringComments(true);
+            FACTORY.setCoalescing(true);
+            FACTORY.setValidating(false);
+        } catch (ParserConfigurationException e) {
+            throw new RuntimeException(e);
+        }
     }
 
     /**
@@ -72,22 +74,10 @@ public class XMLPropertyListParser {
      * @throws javax.xml.parsers.ParserConfigurationException If a document builder for parsing a XML property list
      *                                                        could not be created. This should not occur.
      */
-    private static synchronized DocumentBuilder getDocBuilder() throws ParserConfigurationException {
-        if (docBuilderFactory == null)
-            initDocBuilderFactory();
-        DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
-        docBuilder.setEntityResolver(new EntityResolver() {
-            public InputSource resolveEntity(String publicId, String systemId) {
-                if ("-//Apple Computer//DTD PLIST 1.0//EN".equals(publicId) || // older publicId
-                        "-//Apple//DTD PLIST 1.0//EN".equals(publicId)) { // newer publicId
-                    // return a dummy, zero length DTD so we don't have to fetch
-                    // it from the network.
-                    return new InputSource(new ByteArrayInputStream(new byte[0]));
-                }
-                return null;
-            }
-        });
-        return docBuilder;
+    public static synchronized DocumentBuilder getDocBuilder() throws ParserConfigurationException {
+        DocumentBuilder builder = FACTORY.newDocumentBuilder();
+        builder.setEntityResolver(new PlistDTDResolver());
+        return builder;
     }
 
     /**
@@ -103,12 +93,10 @@ public class XMLPropertyListParser {
      * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
      * @throws java.text.ParseException If a date string could not be parsed.
      */
-    public static NSObject parse(File f) throws ParserConfigurationException, IOException, SAXException, PropertyListFormatException, ParseException {
-        DocumentBuilder docBuilder = getDocBuilder();
-
-        Document doc = docBuilder.parse(f);
+    public static NSObject parse(File f)
+                throws ParserConfigurationException, IOException, SAXException, PropertyListFormatException, ParseException {
 
-        return parse(doc);
+        return parse(getDocBuilder().parse(new FileInputStream(f)));
     }
 
     /**
@@ -123,9 +111,10 @@ public class XMLPropertyListParser {
      * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
      * @throws java.text.ParseException If a date string could not be parsed.
      */
-    public static NSObject parse(final byte[] bytes) throws ParserConfigurationException, ParseException, SAXException, PropertyListFormatException, IOException {
-        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
-        return parse(bis);
+    public static NSObject parse(final byte[] bytes)
+                throws ParserConfigurationException, ParseException, SAXException, PropertyListFormatException, IOException {
+
+        return parse(new ByteArrayInputStream(bytes));
     }
 
     /**
@@ -141,12 +130,10 @@ public class XMLPropertyListParser {
      * @throws com.dd.plist.PropertyListFormatException If the given property list has an invalid format.
      * @throws java.text.ParseException If a date string could not be parsed.
      */
-    public static NSObject parse(InputStream is) throws ParserConfigurationException, IOException, SAXException, PropertyListFormatException, ParseException {
-        DocumentBuilder docBuilder = getDocBuilder();
-
-        Document doc = docBuilder.parse(is);
+    public static NSObject parse(InputStream is)
+                throws ParserConfigurationException, IOException, SAXException, PropertyListFormatException, ParseException {
 
-        return parse(doc);
+        return parse(getDocBuilder().parse(is));
     }
 
     /**
@@ -290,4 +277,24 @@ public class XMLPropertyListParser {
             }
         }
     }
+
+    /**
+     * Resolves only the Apple PLIST DTD.
+     */
+    static class PlistDTDResolver implements EntityResolver {
+        private static final String PLIST_SYSTEMID_1 = "-//Apple Computer//DTD PLIST 1.0//EN";
+        private static final String PLIST_SYSTEMID_2 = "-//Apple//DTD PLIST 1.0//EN";
+
+        PlistDTDResolver() {
+        }
+
+        // Implement EntityResolver
+
+        public InputSource resolveEntity(String publicId, String systemId) {
+            if (PLIST_SYSTEMID_1.equals(publicId) || PLIST_SYSTEMID_2.equals(publicId)) {
+                return new InputSource(XMLPropertyListParser.class.getResourceAsStream("PropertyList-1.0.dtd"));
+            }
+            return null;
+        }
+    }
 }

programming_language: Java