CVE-2015-1833
Description
XML external entity (XXE) vulnerability in Apache Jackrabbit before 2.0.6, 2.2.x before 2.2.14, 2.4.x before 2.4.6, 2.6.x before 2.6.6, 2.8.x before 2.8.1, and 2.10.x before 2.10.1 allows remote attackers to read arbitrary files and send requests to intranet servers via a crafted WebDAV request.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.jackrabbit:jackrabbit-coreMaven | < 2.0.6 | 2.0.6 |
org.apache.jackrabbit:jackrabbit-coreMaven | >= 2.2.0, < 2.2.14 | 2.2.14 |
org.apache.jackrabbit:jackrabbit-coreMaven | >= 2.4.0, < 2.4.6 | 2.4.6 |
org.apache.jackrabbit:jackrabbit-coreMaven | >= 2.6.0, < 2.6.6 | 2.6.6 |
org.apache.jackrabbit:jackrabbit-coreMaven | >= 2.8.0, < 2.8.1 | 2.8.1 |
org.apache.jackrabbit:jackrabbit-coreMaven | >= 2.10.0, < 2.10.1 | 2.10.1 |
Affected products
27cpe:2.3:a:apache:jackrabbit:2.6.4:*:*:*:*:*:*:*+ 26 more
- cpe:2.3:a:apache:jackrabbit:2.6.4:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.6.5:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.8.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.10.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:*:*:*:*:*:*:*:*range: <=2.0.5
- cpe:2.3:a:apache:jackrabbit:2.2.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.2.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.2.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.2.4:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.2.5:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.2.7:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.2.8:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.2.9:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.2.10:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.2.11:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.2.12:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.2.13:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.4.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.4.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.4.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.4.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.4.4:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.4.5:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.6.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.6.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.6.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:jackrabbit:2.6.3:*:*:*:*:*:*:*
Patches
7b7fa1ae39641JCR-3883: Jackrabbit WebDAV bundle susceptible to XXE/XEE attack (CVE-2015-1833) - add missing test classed (ported to 2.0)
2 files changed · +117 −0
jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/xml/ParserTest.java+78 −0 added@@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the \"License\"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an \"AS IS\" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import junit.framework.TestCase; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class ParserTest extends TestCase { + + // see <http://en.wikipedia.org/wiki/Billion_laughs#Details> + public void testBillionLaughs() throws UnsupportedEncodingException { + + String testBody = "<?xml version=\"1.0\"?>" + "<!DOCTYPE lolz [" + " <!ENTITY lol \"lol\">" + " <!ELEMENT lolz (#PCDATA)>" + + " <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">" + + " <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">" + + " <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">" + + " <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">" + + " <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">" + + " <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">" + + " <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">" + + " <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">" + + " <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">" + "]>" + "<lolz>&lol9;</lolz>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + try { + DomUtil.BUILDER_FACTORY.newDocumentBuilder().parse(is); + fail("parsing this document should cause an exception"); + } catch (Exception expected) { + } + } + + public void testExternalEntities() throws IOException { + + String dname = "target"; + String fname = "test.xml"; + + File f = new File(dname, fname); + OutputStream os = new FileOutputStream(f); + os.write("testdata".getBytes()); + os.close(); + + String testBody = "<?xml version='1.0'?>\n<!DOCTYPE foo [" + " <!ENTITY test SYSTEM \"file:" + dname + "/" + fname + "\">" + + "]>\n<foo>&test;</foo>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + try { + Document d = DomUtil.BUILDER_FACTORY.newDocumentBuilder().parse(is); + Element root = d.getDocumentElement(); + String text = DomUtil.getText(root); + fail("parsing this document should cause an exception, but the following external content was included: " + text); + } catch (Exception expected) { + } + } +} \ No newline at end of file
jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/xml/TestAll.java+39 −0 added@@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Test suite that includes all testcases for package org.apache.jackrabbit.webdav.xml. + */ +public class TestAll extends TestCase { + + /** + * Returns a <code>Test</code> suite that executes all tests inside this + * package. + */ + public static Test suite() { + TestSuite suite = new TestSuite("org.apache.jackrabbit.webdav.xml tests"); + + suite.addTestSuite(ParserTest.class); + + return suite; + } +}
26e601934d0fJCR-3883: Jackrabbit WebDAV bundle susceptible to XXE/XEE attack (CVE-2015-1833) (ported to 2.0)
3 files changed · +91 −10
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/client/methods/DavMethodBase.java+3 −1 modified@@ -27,6 +27,7 @@ import org.apache.jackrabbit.webdav.DavServletResponse; import org.apache.jackrabbit.webdav.MultiStatus; import org.apache.jackrabbit.webdav.header.Header; +import org.apache.jackrabbit.webdav.xml.DavDocumentBuilderFactory; import org.apache.jackrabbit.webdav.xml.XmlSerializable; import org.apache.jackrabbit.webdav.xml.DomUtil; import org.slf4j.Logger; @@ -39,6 +40,7 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; + import java.io.IOException; import java.io.InputStream; @@ -49,7 +51,7 @@ public abstract class DavMethodBase extends EntityEnclosingMethod implements Dav private static Logger log = LoggerFactory.getLogger(DavMethodBase.class); - static final DocumentBuilderFactory BUILDER_FACTORY = DomUtil.BUILDER_FACTORY; + static final DavDocumentBuilderFactory BUILDER_FACTORY = DomUtil.BUILDER_FACTORY; private boolean success; private Document responseDocument;
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/xml/DavDocumentBuilderFactory.java+86 −0 added@@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import java.io.IOException; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Custom {@link DocumentBuilderFactory} extended for use in WebDAV. + */ +public class DavDocumentBuilderFactory { + + private static final Logger LOG = LoggerFactory.getLogger(DomUtil.class); + + private final DocumentBuilderFactory DEFAULT_FACTORY = createFactory(); + + private DocumentBuilderFactory BUILDER_FACTORY = DEFAULT_FACTORY; + + private DocumentBuilderFactory createFactory() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setIgnoringComments(true); + factory.setIgnoringElementContentWhitespace(true); + factory.setCoalescing(true); + try { + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (ParserConfigurationException e) { + LOG.warn("Secure XML processing is not supported", e); + } catch (AbstractMethodError e) { + LOG.warn("Secure XML processing is not supported", e); + } + return factory; + } + + public void setFactory(DocumentBuilderFactory documentBuilderFactory) { + LOG.debug("DocumentBuilderFactory changed to: " + documentBuilderFactory); + BUILDER_FACTORY = documentBuilderFactory != null ? documentBuilderFactory : DEFAULT_FACTORY; + } + + /** + * An entity resolver that does not allow external entity resolution. See + * RFC 4918, Section 20.6 + */ + private static final EntityResolver DEFAULT_ENTITY_RESOLVER = new EntityResolver() { + public InputSource resolveEntity(String publicId, String systemId) throws IOException { + LOG.debug("Resolution of external entities in XML payload not supported - publicId: " + publicId + ", systemId: " + + systemId); + throw new IOException("This parser does not support resolution of external entities (publicId: " + publicId + + ", systemId: " + systemId + ")"); + } + }; + + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder db = BUILDER_FACTORY.newDocumentBuilder(); + if (BUILDER_FACTORY == DEFAULT_FACTORY) { + // if this is the default factory: set the default entity resolver as well + db.setEntityResolver(DEFAULT_ENTITY_RESOLVER); + } + db.setErrorHandler(new DefaultHandler()); + return db; + } +}
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/xml/DomUtil.java+2 −9 modified@@ -28,7 +28,6 @@ import org.w3c.dom.Text; import org.w3c.dom.NamedNodeMap; -import javax.xml.parsers.DocumentBuilderFactory; import java.util.ArrayList; import java.util.List; @@ -40,16 +39,10 @@ public class DomUtil { private static Logger log = LoggerFactory.getLogger(DomUtil.class); /** - * Constant for <code>DocumentBuilderFactory</code> which is used + * Constant for <code>DavDocumentBuilderFactory</code> which is used * widely to create new <code>Document</code>s */ - public static DocumentBuilderFactory BUILDER_FACTORY = DocumentBuilderFactory.newInstance(); - static { - BUILDER_FACTORY.setNamespaceAware(true); - BUILDER_FACTORY.setIgnoringComments(true); - BUILDER_FACTORY.setIgnoringElementContentWhitespace(true); - BUILDER_FACTORY.setCoalescing(true); - } + public static DavDocumentBuilderFactory BUILDER_FACTORY = new DavDocumentBuilderFactory(); /** * Returns the value of the named attribute of the current element.
6191b366c607JCR-3883: Jackrabbit WebDAV bundle susceptible to XXE/XEE attack (CVE-2015-1833) (ported to 2.2)
4 files changed · +168 −20
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/xml/DavDocumentBuilderFactory.java+86 −0 added@@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import java.io.IOException; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Custom {@link DocumentBuilderFactory} extended for use in WebDAV. + */ +public class DavDocumentBuilderFactory { + + private static final Logger LOG = LoggerFactory.getLogger(DomUtil.class); + + private final DocumentBuilderFactory DEFAULT_FACTORY = createFactory(); + + private DocumentBuilderFactory BUILDER_FACTORY = DEFAULT_FACTORY; + + private DocumentBuilderFactory createFactory() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setIgnoringComments(true); + factory.setIgnoringElementContentWhitespace(true); + factory.setCoalescing(true); + try { + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (ParserConfigurationException e) { + LOG.warn("Secure XML processing is not supported", e); + } catch (AbstractMethodError e) { + LOG.warn("Secure XML processing is not supported", e); + } + return factory; + } + + public void setFactory(DocumentBuilderFactory documentBuilderFactory) { + LOG.debug("DocumentBuilderFactory changed to: " + documentBuilderFactory); + BUILDER_FACTORY = documentBuilderFactory != null ? documentBuilderFactory : DEFAULT_FACTORY; + } + + /** + * An entity resolver that does not allow external entity resolution. See + * RFC 4918, Section 20.6 + */ + private static final EntityResolver DEFAULT_ENTITY_RESOLVER = new EntityResolver() { + public InputSource resolveEntity(String publicId, String systemId) throws IOException { + LOG.debug("Resolution of external entities in XML payload not supported - publicId: " + publicId + ", systemId: " + + systemId); + throw new IOException("This parser does not support resolution of external entities (publicId: " + publicId + + ", systemId: " + systemId + ")"); + } + }; + + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder db = BUILDER_FACTORY.newDocumentBuilder(); + if (BUILDER_FACTORY == DEFAULT_FACTORY) { + // if this is the default factory: set the default entity resolver as well + db.setEntityResolver(DEFAULT_ENTITY_RESOLVER); + } + db.setErrorHandler(new DefaultHandler()); + return db; + } +}
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/xml/DomUtil.java+3 −20 modified@@ -30,7 +30,6 @@ import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -48,26 +47,10 @@ public class DomUtil { private static Logger log = LoggerFactory.getLogger(DomUtil.class); /** - * Constant for <code>DocumentBuilderFactory</code> which is used + * Constant for <code>DavDocumentBuilderFactory</code> which is used * to create and parse DOM documents. */ - private static DocumentBuilderFactory BUILDER_FACTORY = createFactory(); - - private static DocumentBuilderFactory createFactory() { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setIgnoringComments(true); - factory.setIgnoringElementContentWhitespace(true); - factory.setCoalescing(true); - try { - factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - } catch (ParserConfigurationException e) { - log.warn("Secure XML processing is not supported", e); - } catch (AbstractMethodError e) { - log.warn("Secure XML processing is not supported", e); - } - return factory; - } + private static DavDocumentBuilderFactory BUILDER_FACTORY = new DavDocumentBuilderFactory(); /** * Support the replacement of {@link #BUILDER_FACTORY}. This is useful @@ -80,7 +63,7 @@ private static DocumentBuilderFactory createFactory() { */ public static void setBuilderFactory( DocumentBuilderFactory documentBuilderFactory) { - BUILDER_FACTORY = documentBuilderFactory; + BUILDER_FACTORY.setFactory(documentBuilderFactory); } /**
jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/xml/ParserTest.java+78 −0 added@@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the \"License\"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an \"AS IS\" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import junit.framework.TestCase; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class ParserTest extends TestCase { + + // see <http://en.wikipedia.org/wiki/Billion_laughs#Details> + public void testBillionLaughs() throws UnsupportedEncodingException { + + String testBody = "<?xml version=\"1.0\"?>" + "<!DOCTYPE lolz [" + " <!ENTITY lol \"lol\">" + " <!ELEMENT lolz (#PCDATA)>" + + " <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">" + + " <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">" + + " <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">" + + " <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">" + + " <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">" + + " <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">" + + " <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">" + + " <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">" + + " <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">" + "]>" + "<lolz>&lol9;</lolz>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + try { + DomUtil.parseDocument(is); + fail("parsing this document should cause an exception"); + } catch (Exception expected) { + } + } + + public void testExternalEntities() throws IOException { + + String dname = "target"; + String fname = "test.xml"; + + File f = new File(dname, fname); + OutputStream os = new FileOutputStream(f); + os.write("testdata".getBytes()); + os.close(); + + String testBody = "<?xml version='1.0'?>\n<!DOCTYPE foo [" + " <!ENTITY test SYSTEM \"file:" + dname + "/" + fname + "\">" + + "]>\n<foo>&test;</foo>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + try { + Document d = DomUtil.parseDocument(is); + Element root = d.getDocumentElement(); + String text = DomUtil.getText(root); + fail("parsing this document should cause an exception, but the following external content was included: " + text); + } catch (Exception expected) { + } + } +} \ No newline at end of file
jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/xml/TestAll.java+1 −0 modified@@ -33,6 +33,7 @@ public static Test suite() { TestSuite suite = new TestSuite("org.apache.jackrabbit.webdav.xml tests"); suite.addTestSuite(NamespaceTest.class); + suite.addTestSuite(ParserTest.class); return suite; }
17e9f68f5a3fJCR-3883: Jackrabbit WebDAV bundle susceptible to XXE/XEE attack (CVE-2015-1833) (ported to 2.4)
4 files changed · +234 −26
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/xml/DavDocumentBuilderFactory.java+87 −0 added@@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import java.io.IOException; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Custom {@link DocumentBuilderFactory} extended for use in WebDAV. + */ +public class DavDocumentBuilderFactory { + + private static final Logger LOG = LoggerFactory.getLogger(DomUtil.class); + + private final DocumentBuilderFactory DEFAULT_FACTORY = createFactory(); + + private DocumentBuilderFactory BUILDER_FACTORY = DEFAULT_FACTORY; + + private DocumentBuilderFactory createFactory() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setIgnoringComments(true); + factory.setIgnoringElementContentWhitespace(true); + factory.setCoalescing(true); + try { + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (ParserConfigurationException e) { + LOG.warn("Secure XML processing is not supported", e); + } catch (AbstractMethodError e) { + LOG.warn("Secure XML processing is not supported", e); + } + return factory; + } + + public void setFactory(DocumentBuilderFactory documentBuilderFactory) { + LOG.debug("DocumentBuilderFactory changed to: " + documentBuilderFactory); + BUILDER_FACTORY = documentBuilderFactory != null ? documentBuilderFactory : DEFAULT_FACTORY; + } + + /** + * An entity resolver that does not allow external entity resolution. See + * RFC 4918, Section 20.6 + */ + private static final EntityResolver DEFAULT_ENTITY_RESOLVER = new EntityResolver() { + @Override + public InputSource resolveEntity(String publicId, String systemId) throws IOException { + LOG.debug("Resolution of external entities in XML payload not supported - publicId: " + publicId + ", systemId: " + + systemId); + throw new IOException("This parser does not support resolution of external entities (publicId: " + publicId + + ", systemId: " + systemId + ")"); + } + }; + + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder db = BUILDER_FACTORY.newDocumentBuilder(); + if (BUILDER_FACTORY == DEFAULT_FACTORY) { + // if this is the default factory: set the default entity resolver as well + db.setEntityResolver(DEFAULT_ENTITY_RESOLVER); + } + db.setErrorHandler(new DefaultHandler()); + return db; + } +}
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/xml/DomUtil.java+3 −26 modified@@ -28,9 +28,7 @@ import org.w3c.dom.Text; import org.w3c.dom.NamedNodeMap; import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; -import javax.xml.XMLConstants; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -56,26 +54,10 @@ public class DomUtil { private static Logger log = LoggerFactory.getLogger(DomUtil.class); /** - * Constant for <code>DocumentBuilderFactory</code> which is used + * Constant for <code>DavDocumentBuilderFactory</code> which is used * to create and parse DOM documents. */ - private static DocumentBuilderFactory BUILDER_FACTORY = createFactory(); - - private static DocumentBuilderFactory createFactory() { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setIgnoringComments(true); - factory.setIgnoringElementContentWhitespace(true); - factory.setCoalescing(true); - try { - factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - } catch (ParserConfigurationException e) { - log.warn("Secure XML processing is not supported", e); - } catch (AbstractMethodError e) { - log.warn("Secure XML processing is not supported", e); - } - return factory; - } + private static final DavDocumentBuilderFactory BUILDER_FACTORY = new DavDocumentBuilderFactory(); /** * Support the replacement of {@link #BUILDER_FACTORY}. This is useful @@ -88,7 +70,7 @@ private static DocumentBuilderFactory createFactory() { */ public static void setBuilderFactory( DocumentBuilderFactory documentBuilderFactory) { - BUILDER_FACTORY = documentBuilderFactory; + BUILDER_FACTORY.setFactory(documentBuilderFactory); } /** @@ -119,11 +101,6 @@ public static Document createDocument() public static Document parseDocument(InputStream stream) throws ParserConfigurationException, SAXException, IOException { DocumentBuilder docBuilder = BUILDER_FACTORY.newDocumentBuilder(); - - // Set an error handler to prevent parsers from printing error messages - // to standard output! - docBuilder.setErrorHandler(new DefaultHandler()); - return docBuilder.parse(stream); }
jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/xml/ParserTest.java+143 −0 added@@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the \"License\"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an \"AS IS\" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import junit.framework.TestCase; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +public class ParserTest extends TestCase { + + // see <http://en.wikipedia.org/wiki/Billion_laughs#Details> + public void testBillionLaughs() throws UnsupportedEncodingException { + + String testBody = "<?xml version=\"1.0\"?>" + "<!DOCTYPE lolz [" + " <!ENTITY lol \"lol\">" + " <!ELEMENT lolz (#PCDATA)>" + + " <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">" + + " <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">" + + " <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">" + + " <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">" + + " <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">" + + " <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">" + + " <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">" + + " <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">" + + " <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">" + "]>" + "<lolz>&lol9;</lolz>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + try { + DomUtil.parseDocument(is); + fail("parsing this document should cause an exception"); + } catch (Exception expected) { + } + } + + public void testExternalEntities() throws IOException { + + String dname = "target"; + String fname = "test.xml"; + + File f = new File(dname, fname); + OutputStream os = new FileOutputStream(f); + os.write("testdata".getBytes()); + os.close(); + + String testBody = "<?xml version='1.0'?>\n<!DOCTYPE foo [" + " <!ENTITY test SYSTEM \"file:" + dname + "/" + fname + "\">" + + "]>\n<foo>&test;</foo>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + try { + Document d = DomUtil.parseDocument(is); + Element root = d.getDocumentElement(); + String text = DomUtil.getText(root); + fail("parsing this document should cause an exception, but the following external content was included: " + text); + } catch (Exception expected) { + } + } + + public void testCustomEntityResolver() throws ParserConfigurationException, SAXException, IOException { + + try { + DocumentBuilderFactory dbf = new DocumentBuilderFactory() { + + DocumentBuilderFactory def = DocumentBuilderFactory.newInstance(); + + @Override + public void setFeature(String name, boolean value) throws ParserConfigurationException { + def.setFeature(name, value); + } + + @Override + public void setAttribute(String name, Object value) throws IllegalArgumentException { + def.setAttribute(name, value); + } + + @Override + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder db = def.newDocumentBuilder(); + db.setEntityResolver(new EntityResolver() { + @Override + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + if ("foo:test".equals(systemId)) { + return new InputSource(new ByteArrayInputStream("foo&bar".getBytes("UTF-8"))); + } else { + return null; + } + } + }); + return db; + } + + @Override + public boolean getFeature(String name) throws ParserConfigurationException { + return def.getFeature(name); + } + + @Override + public Object getAttribute(String name) throws IllegalArgumentException { + return def.getAttribute(name); + } + }; + + DomUtil.setBuilderFactory(dbf); + String testBody = "<?xml version='1.0'?>\n<!DOCTYPE foo [" + " <!ENTITY test SYSTEM \"foo:test\">" + + "]>\n<foo>&test;</foo>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + Document d = DomUtil.parseDocument(is); + Element root = d.getDocumentElement(); + String text = DomUtil.getText(root); + assertEquals("custom entity resolver apparently not called", "foo&bar", text); + } finally { + DomUtil.setBuilderFactory(null); + } + } +} \ No newline at end of file
jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/xml/TestAll.java+1 −0 modified@@ -33,6 +33,7 @@ public static Test suite() { TestSuite suite = new TestSuite("org.apache.jackrabbit.webdav.xml tests"); suite.addTestSuite(NamespaceTest.class); + suite.addTestSuite(ParserTest.class); return suite; }
89c5c4ed6ab2JCR-3883: Jackrabbit WebDAV bundle susceptible to XXE/XEE attack (CVE-2015-1833) (ported to 2.6)
4 files changed · +234 −26
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/xml/DavDocumentBuilderFactory.java+87 −0 added@@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import java.io.IOException; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Custom {@link DocumentBuilderFactory} extended for use in WebDAV. + */ +public class DavDocumentBuilderFactory { + + private static final Logger LOG = LoggerFactory.getLogger(DomUtil.class); + + private final DocumentBuilderFactory DEFAULT_FACTORY = createFactory(); + + private DocumentBuilderFactory BUILDER_FACTORY = DEFAULT_FACTORY; + + private DocumentBuilderFactory createFactory() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setIgnoringComments(true); + factory.setIgnoringElementContentWhitespace(true); + factory.setCoalescing(true); + try { + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (ParserConfigurationException e) { + LOG.warn("Secure XML processing is not supported", e); + } catch (AbstractMethodError e) { + LOG.warn("Secure XML processing is not supported", e); + } + return factory; + } + + public void setFactory(DocumentBuilderFactory documentBuilderFactory) { + LOG.debug("DocumentBuilderFactory changed to: " + documentBuilderFactory); + BUILDER_FACTORY = documentBuilderFactory != null ? documentBuilderFactory : DEFAULT_FACTORY; + } + + /** + * An entity resolver that does not allow external entity resolution. See + * RFC 4918, Section 20.6 + */ + private static final EntityResolver DEFAULT_ENTITY_RESOLVER = new EntityResolver() { + @Override + public InputSource resolveEntity(String publicId, String systemId) throws IOException { + LOG.debug("Resolution of external entities in XML payload not supported - publicId: " + publicId + ", systemId: " + + systemId); + throw new IOException("This parser does not support resolution of external entities (publicId: " + publicId + + ", systemId: " + systemId + ")"); + } + }; + + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder db = BUILDER_FACTORY.newDocumentBuilder(); + if (BUILDER_FACTORY == DEFAULT_FACTORY) { + // if this is the default factory: set the default entity resolver as well + db.setEntityResolver(DEFAULT_ENTITY_RESOLVER); + } + db.setErrorHandler(new DefaultHandler()); + return db; + } +}
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/xml/DomUtil.java+3 −26 modified@@ -28,9 +28,7 @@ import org.w3c.dom.Text; import org.w3c.dom.NamedNodeMap; import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; -import javax.xml.XMLConstants; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -56,26 +54,10 @@ public class DomUtil { private static Logger log = LoggerFactory.getLogger(DomUtil.class); /** - * Constant for <code>DocumentBuilderFactory</code> which is used + * Constant for <code>DavDocumentBuilderFactory</code> which is used * to create and parse DOM documents. */ - private static DocumentBuilderFactory BUILDER_FACTORY = createFactory(); - - private static DocumentBuilderFactory createFactory() { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setIgnoringComments(true); - factory.setIgnoringElementContentWhitespace(true); - factory.setCoalescing(true); - try { - factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - } catch (ParserConfigurationException e) { - log.warn("Secure XML processing is not supported", e); - } catch (AbstractMethodError e) { - log.warn("Secure XML processing is not supported", e); - } - return factory; - } + private static final DavDocumentBuilderFactory BUILDER_FACTORY = new DavDocumentBuilderFactory(); /** * Support the replacement of {@link #BUILDER_FACTORY}. This is useful @@ -88,7 +70,7 @@ private static DocumentBuilderFactory createFactory() { */ public static void setBuilderFactory( DocumentBuilderFactory documentBuilderFactory) { - BUILDER_FACTORY = documentBuilderFactory; + BUILDER_FACTORY.setFactory(documentBuilderFactory); } /** @@ -119,11 +101,6 @@ public static Document createDocument() public static Document parseDocument(InputStream stream) throws ParserConfigurationException, SAXException, IOException { DocumentBuilder docBuilder = BUILDER_FACTORY.newDocumentBuilder(); - - // Set an error handler to prevent parsers from printing error messages - // to standard output! - docBuilder.setErrorHandler(new DefaultHandler()); - return docBuilder.parse(stream); }
jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/xml/ParserTest.java+143 −0 added@@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the \"License\"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an \"AS IS\" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import junit.framework.TestCase; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +public class ParserTest extends TestCase { + + // see <http://en.wikipedia.org/wiki/Billion_laughs#Details> + public void testBillionLaughs() throws UnsupportedEncodingException { + + String testBody = "<?xml version=\"1.0\"?>" + "<!DOCTYPE lolz [" + " <!ENTITY lol \"lol\">" + " <!ELEMENT lolz (#PCDATA)>" + + " <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">" + + " <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">" + + " <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">" + + " <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">" + + " <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">" + + " <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">" + + " <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">" + + " <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">" + + " <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">" + "]>" + "<lolz>&lol9;</lolz>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + try { + DomUtil.parseDocument(is); + fail("parsing this document should cause an exception"); + } catch (Exception expected) { + } + } + + public void testExternalEntities() throws IOException { + + String dname = "target"; + String fname = "test.xml"; + + File f = new File(dname, fname); + OutputStream os = new FileOutputStream(f); + os.write("testdata".getBytes()); + os.close(); + + String testBody = "<?xml version='1.0'?>\n<!DOCTYPE foo [" + " <!ENTITY test SYSTEM \"file:" + dname + "/" + fname + "\">" + + "]>\n<foo>&test;</foo>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + try { + Document d = DomUtil.parseDocument(is); + Element root = d.getDocumentElement(); + String text = DomUtil.getText(root); + fail("parsing this document should cause an exception, but the following external content was included: " + text); + } catch (Exception expected) { + } + } + + public void testCustomEntityResolver() throws ParserConfigurationException, SAXException, IOException { + + try { + DocumentBuilderFactory dbf = new DocumentBuilderFactory() { + + DocumentBuilderFactory def = DocumentBuilderFactory.newInstance(); + + @Override + public void setFeature(String name, boolean value) throws ParserConfigurationException { + def.setFeature(name, value); + } + + @Override + public void setAttribute(String name, Object value) throws IllegalArgumentException { + def.setAttribute(name, value); + } + + @Override + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder db = def.newDocumentBuilder(); + db.setEntityResolver(new EntityResolver() { + @Override + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + if ("foo:test".equals(systemId)) { + return new InputSource(new ByteArrayInputStream("foo&bar".getBytes("UTF-8"))); + } else { + return null; + } + } + }); + return db; + } + + @Override + public boolean getFeature(String name) throws ParserConfigurationException { + return def.getFeature(name); + } + + @Override + public Object getAttribute(String name) throws IllegalArgumentException { + return def.getAttribute(name); + } + }; + + DomUtil.setBuilderFactory(dbf); + String testBody = "<?xml version='1.0'?>\n<!DOCTYPE foo [" + " <!ENTITY test SYSTEM \"foo:test\">" + + "]>\n<foo>&test;</foo>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + Document d = DomUtil.parseDocument(is); + Element root = d.getDocumentElement(); + String text = DomUtil.getText(root); + assertEquals("custom entity resolver apparently not called", "foo&bar", text); + } finally { + DomUtil.setBuilderFactory(null); + } + } +} \ No newline at end of file
jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/xml/TestAll.java+1 −0 modified@@ -33,6 +33,7 @@ public static Test suite() { TestSuite suite = new TestSuite("org.apache.jackrabbit.webdav.xml tests"); suite.addTestSuite(NamespaceTest.class); + suite.addTestSuite(ParserTest.class); return suite; }
ddf9a3cd4083JCR-3883: Jackrabbit WebDAV bundle susceptible to XXE/XEE attack (CVE-2015-1833) (ported to 2.8)
4 files changed · +234 −26
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/xml/DavDocumentBuilderFactory.java+87 −0 added@@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import java.io.IOException; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Custom {@link DocumentBuilderFactory} extended for use in WebDAV. + */ +public class DavDocumentBuilderFactory { + + private static final Logger LOG = LoggerFactory.getLogger(DomUtil.class); + + private final DocumentBuilderFactory DEFAULT_FACTORY = createFactory(); + + private DocumentBuilderFactory BUILDER_FACTORY = DEFAULT_FACTORY; + + private DocumentBuilderFactory createFactory() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setIgnoringComments(true); + factory.setIgnoringElementContentWhitespace(true); + factory.setCoalescing(true); + try { + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (ParserConfigurationException e) { + LOG.warn("Secure XML processing is not supported", e); + } catch (AbstractMethodError e) { + LOG.warn("Secure XML processing is not supported", e); + } + return factory; + } + + public void setFactory(DocumentBuilderFactory documentBuilderFactory) { + LOG.debug("DocumentBuilderFactory changed to: " + documentBuilderFactory); + BUILDER_FACTORY = documentBuilderFactory != null ? documentBuilderFactory : DEFAULT_FACTORY; + } + + /** + * An entity resolver that does not allow external entity resolution. See + * RFC 4918, Section 20.6 + */ + private static final EntityResolver DEFAULT_ENTITY_RESOLVER = new EntityResolver() { + @Override + public InputSource resolveEntity(String publicId, String systemId) throws IOException { + LOG.debug("Resolution of external entities in XML payload not supported - publicId: " + publicId + ", systemId: " + + systemId); + throw new IOException("This parser does not support resolution of external entities (publicId: " + publicId + + ", systemId: " + systemId + ")"); + } + }; + + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder db = BUILDER_FACTORY.newDocumentBuilder(); + if (BUILDER_FACTORY == DEFAULT_FACTORY) { + // if this is the default factory: set the default entity resolver as well + db.setEntityResolver(DEFAULT_ENTITY_RESOLVER); + } + db.setErrorHandler(new DefaultHandler()); + return db; + } +}
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/xml/DomUtil.java+3 −26 modified@@ -28,9 +28,7 @@ import org.w3c.dom.Text; import org.w3c.dom.NamedNodeMap; import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; -import javax.xml.XMLConstants; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -56,26 +54,10 @@ public class DomUtil { private static Logger log = LoggerFactory.getLogger(DomUtil.class); /** - * Constant for <code>DocumentBuilderFactory</code> which is used + * Constant for <code>DavDocumentBuilderFactory</code> which is used * to create and parse DOM documents. */ - private static DocumentBuilderFactory BUILDER_FACTORY = createFactory(); - - private static DocumentBuilderFactory createFactory() { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setIgnoringComments(true); - factory.setIgnoringElementContentWhitespace(true); - factory.setCoalescing(true); - try { - factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - } catch (ParserConfigurationException e) { - log.warn("Secure XML processing is not supported", e); - } catch (AbstractMethodError e) { - log.warn("Secure XML processing is not supported", e); - } - return factory; - } + private static final DavDocumentBuilderFactory BUILDER_FACTORY = new DavDocumentBuilderFactory(); /** * Support the replacement of {@link #BUILDER_FACTORY}. This is useful @@ -88,7 +70,7 @@ private static DocumentBuilderFactory createFactory() { */ public static void setBuilderFactory( DocumentBuilderFactory documentBuilderFactory) { - BUILDER_FACTORY = documentBuilderFactory; + BUILDER_FACTORY.setFactory(documentBuilderFactory); } /** @@ -119,11 +101,6 @@ public static Document createDocument() public static Document parseDocument(InputStream stream) throws ParserConfigurationException, SAXException, IOException { DocumentBuilder docBuilder = BUILDER_FACTORY.newDocumentBuilder(); - - // Set an error handler to prevent parsers from printing error messages - // to standard output! - docBuilder.setErrorHandler(new DefaultHandler()); - return docBuilder.parse(stream); }
jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/xml/ParserTest.java+143 −0 added@@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the \"License\"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an \"AS IS\" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import junit.framework.TestCase; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +public class ParserTest extends TestCase { + + // see <http://en.wikipedia.org/wiki/Billion_laughs#Details> + public void testBillionLaughs() throws UnsupportedEncodingException { + + String testBody = "<?xml version=\"1.0\"?>" + "<!DOCTYPE lolz [" + " <!ENTITY lol \"lol\">" + " <!ELEMENT lolz (#PCDATA)>" + + " <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">" + + " <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">" + + " <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">" + + " <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">" + + " <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">" + + " <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">" + + " <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">" + + " <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">" + + " <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">" + "]>" + "<lolz>&lol9;</lolz>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + try { + DomUtil.parseDocument(is); + fail("parsing this document should cause an exception"); + } catch (Exception expected) { + } + } + + public void testExternalEntities() throws IOException { + + String dname = "target"; + String fname = "test.xml"; + + File f = new File(dname, fname); + OutputStream os = new FileOutputStream(f); + os.write("testdata".getBytes()); + os.close(); + + String testBody = "<?xml version='1.0'?>\n<!DOCTYPE foo [" + " <!ENTITY test SYSTEM \"file:" + dname + "/" + fname + "\">" + + "]>\n<foo>&test;</foo>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + try { + Document d = DomUtil.parseDocument(is); + Element root = d.getDocumentElement(); + String text = DomUtil.getText(root); + fail("parsing this document should cause an exception, but the following external content was included: " + text); + } catch (Exception expected) { + } + } + + public void testCustomEntityResolver() throws ParserConfigurationException, SAXException, IOException { + + try { + DocumentBuilderFactory dbf = new DocumentBuilderFactory() { + + DocumentBuilderFactory def = DocumentBuilderFactory.newInstance(); + + @Override + public void setFeature(String name, boolean value) throws ParserConfigurationException { + def.setFeature(name, value); + } + + @Override + public void setAttribute(String name, Object value) throws IllegalArgumentException { + def.setAttribute(name, value); + } + + @Override + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder db = def.newDocumentBuilder(); + db.setEntityResolver(new EntityResolver() { + @Override + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + if ("foo:test".equals(systemId)) { + return new InputSource(new ByteArrayInputStream("foo&bar".getBytes("UTF-8"))); + } else { + return null; + } + } + }); + return db; + } + + @Override + public boolean getFeature(String name) throws ParserConfigurationException { + return def.getFeature(name); + } + + @Override + public Object getAttribute(String name) throws IllegalArgumentException { + return def.getAttribute(name); + } + }; + + DomUtil.setBuilderFactory(dbf); + String testBody = "<?xml version='1.0'?>\n<!DOCTYPE foo [" + " <!ENTITY test SYSTEM \"foo:test\">" + + "]>\n<foo>&test;</foo>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + Document d = DomUtil.parseDocument(is); + Element root = d.getDocumentElement(); + String text = DomUtil.getText(root); + assertEquals("custom entity resolver apparently not called", "foo&bar", text); + } finally { + DomUtil.setBuilderFactory(null); + } + } +} \ No newline at end of file
jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/xml/TestAll.java+1 −0 modified@@ -33,6 +33,7 @@ public static Test suite() { TestSuite suite = new TestSuite("org.apache.jackrabbit.webdav.xml tests"); suite.addTestSuite(NamespaceTest.class); + suite.addTestSuite(ParserTest.class); return suite; }
3903739363b7JCR-3883: Jackrabbit WebDAV bundle susceptible to XXE/XEE attack
4 files changed · +234 −26
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/xml/DavDocumentBuilderFactory.java+87 −0 added@@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import java.io.IOException; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Custom {@link DocumentBuilderFactory} extended for use in WebDAV. + */ +public class DavDocumentBuilderFactory { + + private static final Logger LOG = LoggerFactory.getLogger(DomUtil.class); + + private final DocumentBuilderFactory DEFAULT_FACTORY = createFactory(); + + private DocumentBuilderFactory BUILDER_FACTORY = DEFAULT_FACTORY; + + private DocumentBuilderFactory createFactory() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setIgnoringComments(true); + factory.setIgnoringElementContentWhitespace(true); + factory.setCoalescing(true); + try { + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (ParserConfigurationException e) { + LOG.warn("Secure XML processing is not supported", e); + } catch (AbstractMethodError e) { + LOG.warn("Secure XML processing is not supported", e); + } + return factory; + } + + public void setFactory(DocumentBuilderFactory documentBuilderFactory) { + LOG.debug("DocumentBuilderFactory changed to: " + documentBuilderFactory); + BUILDER_FACTORY = documentBuilderFactory != null ? documentBuilderFactory : DEFAULT_FACTORY; + } + + /** + * An entity resolver that does not allow external entity resolution. See + * RFC 4918, Section 20.6 + */ + private static final EntityResolver DEFAULT_ENTITY_RESOLVER = new EntityResolver() { + @Override + public InputSource resolveEntity(String publicId, String systemId) throws IOException { + LOG.debug("Resolution of external entities in XML payload not supported - publicId: " + publicId + ", systemId: " + + systemId); + throw new IOException("This parser does not support resolution of external entities (publicId: " + publicId + + ", systemId: " + systemId + ")"); + } + }; + + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder db = BUILDER_FACTORY.newDocumentBuilder(); + if (BUILDER_FACTORY == DEFAULT_FACTORY) { + // if this is the default factory: set the default entity resolver as well + db.setEntityResolver(DEFAULT_ENTITY_RESOLVER); + } + db.setErrorHandler(new DefaultHandler()); + return db; + } +}
jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/xml/DomUtil.java+3 −26 modified@@ -28,9 +28,7 @@ import org.w3c.dom.Text; import org.w3c.dom.NamedNodeMap; import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; -import javax.xml.XMLConstants; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -56,26 +54,10 @@ public class DomUtil { private static Logger log = LoggerFactory.getLogger(DomUtil.class); /** - * Constant for <code>DocumentBuilderFactory</code> which is used + * Constant for <code>DavDocumentBuilderFactory</code> which is used * to create and parse DOM documents. */ - private static DocumentBuilderFactory BUILDER_FACTORY = createFactory(); - - private static DocumentBuilderFactory createFactory() { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setIgnoringComments(true); - factory.setIgnoringElementContentWhitespace(true); - factory.setCoalescing(true); - try { - factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - } catch (ParserConfigurationException e) { - log.warn("Secure XML processing is not supported", e); - } catch (AbstractMethodError e) { - log.warn("Secure XML processing is not supported", e); - } - return factory; - } + private static final DavDocumentBuilderFactory BUILDER_FACTORY = new DavDocumentBuilderFactory(); /** * Support the replacement of {@link #BUILDER_FACTORY}. This is useful @@ -88,7 +70,7 @@ private static DocumentBuilderFactory createFactory() { */ public static void setBuilderFactory( DocumentBuilderFactory documentBuilderFactory) { - BUILDER_FACTORY = documentBuilderFactory; + BUILDER_FACTORY.setFactory(documentBuilderFactory); } /** @@ -119,11 +101,6 @@ public static Document createDocument() public static Document parseDocument(InputStream stream) throws ParserConfigurationException, SAXException, IOException { DocumentBuilder docBuilder = BUILDER_FACTORY.newDocumentBuilder(); - - // Set an error handler to prevent parsers from printing error messages - // to standard output! - docBuilder.setErrorHandler(new DefaultHandler()); - return docBuilder.parse(stream); }
jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/xml/ParserTest.java+143 −0 added@@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the \"License\"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an \"AS IS\" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.webdav.xml; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import junit.framework.TestCase; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +public class ParserTest extends TestCase { + + // see <http://en.wikipedia.org/wiki/Billion_laughs#Details> + public void testBillionLaughs() throws UnsupportedEncodingException { + + String testBody = "<?xml version=\"1.0\"?>" + "<!DOCTYPE lolz [" + " <!ENTITY lol \"lol\">" + " <!ELEMENT lolz (#PCDATA)>" + + " <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">" + + " <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">" + + " <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">" + + " <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">" + + " <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">" + + " <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">" + + " <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">" + + " <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">" + + " <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">" + "]>" + "<lolz>&lol9;</lolz>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + try { + DomUtil.parseDocument(is); + fail("parsing this document should cause an exception"); + } catch (Exception expected) { + } + } + + public void testExternalEntities() throws IOException { + + String dname = "target"; + String fname = "test.xml"; + + File f = new File(dname, fname); + OutputStream os = new FileOutputStream(f); + os.write("testdata".getBytes()); + os.close(); + + String testBody = "<?xml version='1.0'?>\n<!DOCTYPE foo [" + " <!ENTITY test SYSTEM \"file:" + dname + "/" + fname + "\">" + + "]>\n<foo>&test;</foo>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + try { + Document d = DomUtil.parseDocument(is); + Element root = d.getDocumentElement(); + String text = DomUtil.getText(root); + fail("parsing this document should cause an exception, but the following external content was included: " + text); + } catch (Exception expected) { + } + } + + public void testCustomEntityResolver() throws ParserConfigurationException, SAXException, IOException { + + try { + DocumentBuilderFactory dbf = new DocumentBuilderFactory() { + + DocumentBuilderFactory def = DocumentBuilderFactory.newInstance(); + + @Override + public void setFeature(String name, boolean value) throws ParserConfigurationException { + def.setFeature(name, value); + } + + @Override + public void setAttribute(String name, Object value) throws IllegalArgumentException { + def.setAttribute(name, value); + } + + @Override + public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilder db = def.newDocumentBuilder(); + db.setEntityResolver(new EntityResolver() { + @Override + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + if ("foo:test".equals(systemId)) { + return new InputSource(new ByteArrayInputStream("foo&bar".getBytes("UTF-8"))); + } else { + return null; + } + } + }); + return db; + } + + @Override + public boolean getFeature(String name) throws ParserConfigurationException { + return def.getFeature(name); + } + + @Override + public Object getAttribute(String name) throws IllegalArgumentException { + return def.getAttribute(name); + } + }; + + DomUtil.setBuilderFactory(dbf); + String testBody = "<?xml version='1.0'?>\n<!DOCTYPE foo [" + " <!ENTITY test SYSTEM \"foo:test\">" + + "]>\n<foo>&test;</foo>"; + InputStream is = new ByteArrayInputStream(testBody.getBytes("UTF-8")); + + Document d = DomUtil.parseDocument(is); + Element root = d.getDocumentElement(); + String text = DomUtil.getText(root); + assertEquals("custom entity resolver apparently not called", "foo&bar", text); + } finally { + DomUtil.setBuilderFactory(null); + } + } +} \ No newline at end of file
jackrabbit-webdav/src/test/java/org/apache/jackrabbit/webdav/xml/TestAll.java+1 −0 modified@@ -33,6 +33,7 @@ public static Test suite() { TestSuite suite = new TestSuite("org.apache.jackrabbit.webdav.xml tests"); suite.addTestSuite(NamespaceTest.class); + suite.addTestSuite(ParserTest.class); return suite; }
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
18- www.exploit-db.com/exploits/37110/nvdExploit
- mail-archives.apache.org/mod_mbox/jackrabbit-announce/201505.mbox/%3C555DA644.8080908%40greenbytes.de%3EnvdVendor AdvisoryWEB
- www.apache.org/dist/jackrabbit/2.10.1/RELEASE-NOTES.txtnvdVendor AdvisoryWEB
- github.com/advisories/GHSA-9284-j4c9-779qghsaADVISORY
- issues.apache.org/jira/browse/JCR-3883nvdVendor AdvisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2015-1833ghsaADVISORY
- packetstormsecurity.com/files/132005/Jackrabbit-WebDAV-XXE-Injection.htmlnvdWEB
- www.debian.org/security/2015/dsa-3298nvdWEB
- github.com/apache/jackrabbit/commit/17e9f68f5a3f05ded20569777a7b07422680612dghsaWEB
- github.com/apache/jackrabbit/commit/26e601934d0f439f0a61d62265f52936d79df40dghsaWEB
- github.com/apache/jackrabbit/commit/3903739363b79deb7579802fbc27b9b7448218b2ghsaWEB
- github.com/apache/jackrabbit/commit/6191b366c607e65325a0116097aca8a359b36486ghsaWEB
- github.com/apache/jackrabbit/commit/89c5c4ed6ab250ad609829517f167d2dbe0abdd0ghsaWEB
- github.com/apache/jackrabbit/commit/b7fa1ae39641936872617ff95363353b0345b777ghsaWEB
- github.com/apache/jackrabbit/commit/ddf9a3cd408397d0805917299c4114b09449373dghsaWEB
- www.exploit-db.com/exploits/37110ghsaWEB
- www.securityfocus.com/archive/1/535582/100/0/threadednvd
- www.securityfocus.com/bid/74761nvd
News mentions
0No linked articles in our index yet.