CVE-2014-8125 (published 2015-04-21T17:59Z)

XML external entity (XXE) vulnerability in Drools and jBPM before 6.2.0 allows remote attackers to read arbitrary files or possibly have other unspecified impact via a crafted BPMN2 file.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)

Weakness information:
cwe_id: NVD-CWE-Other
cwe_name: Other
description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/droolsjbpm/jbpm
commit_details: repo_url: https://github.com/droolsjbpm/jbpm
author: Maciej Swiderski
author_date: 2014-12-22 14:17:29+01:00
msg: BZ-1169553 - (CVE-2014-8125) EMBARGOED CVE-2014-8125 jBPM: BPMN2 file processing XXE in Process Execution
repository: repo_url: https://github.com/droolsjbpm/jbpm
repo_name: kiegroup/jbpm
description: a Business Process Management (BPM) Suite
repo_language: Java
owner: droolsjbpm
file_changes: filename: StandaloneBPMNProcessTest.java
change_type: ModificationType.MODIFY
diff: @@ -17,6 +17,8 @@
 package org.jbpm.bpmn2;
 
 import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -26,6 +28,7 @@ import java.util.Map;
 
 import javax.xml.parsers.DocumentBuilderFactory;
 
+import org.drools.core.util.IoUtils;
 import org.jbpm.bpmn2.handler.ReceiveTaskHandler;
 import org.jbpm.bpmn2.handler.SendTaskHandler;
 import org.jbpm.bpmn2.handler.ServiceTaskHandler;
@@ -47,6 +50,7 @@ import org.junit.runners.Parameterized.Parameters;
 import org.kie.api.KieBase;
 import org.kie.api.event.process.DefaultProcessEventListener;
 import org.kie.api.event.process.ProcessStartedEvent;
+import org.kie.api.io.Resource;
 import org.kie.api.io.ResourceType;
 import org.kie.api.runtime.KieSession;
 import org.kie.api.runtime.process.ProcessInstance;
@@ -884,6 +888,45 @@ public class StandaloneBPMNProcessTest extends JbpmBpmn2TestCase {
         runTestSignallingExceptionServiceTask(ksession);
     }
     
+    @Test
+    public void testXXEProcessVulnerability() throws Exception {
+    	Resource processResource = ResourceFactory.newClassPathResource("xxe-protection/BPMN2-XXE-Process.bpmn2");
+    	
+    	File dtdFile = new File("src/test/resources/xxe-protection/external.dtd");
+    	assertTrue(dtdFile.exists());
+    	
+    	String dtdContent = IoUtils.readFileAsString(dtdFile);
+    	dtdContent = dtdContent.replaceAll("@@PATH@@", dtdFile.getParentFile().getAbsolutePath());
+    	
+    	IoUtils.write(dtdFile, dtdContent.getBytes("UTF-8"));
+    	
+    	byte[] data = IoUtils.readBytesFromInputStream(processResource.getInputStream());
+    	String processAsString = new String(data, "UTF-8");
+    	// replace place holders with actual paths
+    	File testFiles = new File("src/test/resources/xxe-protection");
+    	
+    	assertTrue(testFiles.exists());
+    	
+    	String path = testFiles.getAbsolutePath();
+    	processAsString = processAsString.replaceAll("@@PATH@@", path);
+    	
+    	Resource resource = ResourceFactory.newReaderResource(new StringReader(processAsString));
+    	resource.setSourcePath(processResource.getSourcePath());
+    	resource.setTargetPath(processResource.getTargetPath());
+    	
+        KieBase kbase = createKnowledgeBaseFromResources(resource);
+        KieSession ksession = createKnowledgeSession(kbase);
+        ProcessInstance processInstance = ksession.startProcess("async-examples.bp1");
+        
+        String var1 = getProcessVarValue(processInstance, "testScript1");
+        String var2 = getProcessVarValue(processInstance, "testScript2");
+        
+        assertNull(var1);
+        assertNull(var2);
+        
+        assertTrue(processInstance.getState() == ProcessInstance.STATE_COMPLETED);
+    }
+    
     public static void runTestSignallingExceptionServiceTask(KieSession ksession) throws Exception {
         // Setup
         String eventType = "exception-signal";

programming_language: Java
filename: BPMN2-XXE-Process.bpmn2
change_type: ModificationType.ADD
diff: @@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+    <!DOCTYPE foo [
+        <!ELEMENT foo ANY >
+        <!ENTITY author "JDL">
+        <!ENTITY scriptName1 "NewScript1">
+        <!ENTITY scriptName2 "NewScript2">
+        <!ENTITY xxe1 SYSTEM "file://@@PATH@@/Text1.txt" >        
+        <!ENTITY % extdtd SYSTEM "file://@@PATH@@/external.dtd" >
+        %extdtd;
+]>
+<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.omg.org/bpmn20" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:bpsim="http://www.bpsim.org/schemas/1.0" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:drools="http://www.jboss.org/drools" id="_P4xkIF3VEeSfO7lCL83Qdw" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd http://www.jboss.org/drools drools.xsd http://www.bpsim.org/schemas/1.0 bpsim.xsd" expressionLanguage="http://www.mvel.org/2.0" targetNamespace="http://www.omg.org/bpmn20" typeLanguage="http://www.java.com/javaTypes">
+  <bpmn2:itemDefinition id="_testItem" structureRef="String" />
+  <bpmn2:process id="async-examples.bp1" drools:packageName="org.jbpm" drools:version="1.0" name="bp1" isExecutable="true">
+    <bpmn2:property id="testScript1" itemSubjectRef="_testItem"/>
+    <bpmn2:property id="testScript2" itemSubjectRef="_testItem"/>
+    <bpmn2:startEvent id="_5A035F23-6CA6-4EC4-8EE5-A5E87B0B7C19" drools:bgcolor="#9acd32" drools:selectable="true" name="">
+      <bpmn2:outgoing>_43A53630-6A27-4E1C-AD13-F87924127544</bpmn2:outgoing>
+    </bpmn2:startEvent>
+    <bpmn2:scriptTask id="_5C1B77ED-96D1-425C-921B-76F58B543385" drools:selectable="true" name="&scriptName1;" scriptFormat="http://www.java.com/java">
+      <bpmn2:incoming>_43A53630-6A27-4E1C-AD13-F87924127544</bpmn2:incoming>
+      <bpmn2:outgoing>_F4203272-5ED9-4E6D-9E23-4A992BA2E9F8</bpmn2:outgoing>
+      <bpmn2:script>&xxe1;</bpmn2:script>
+    </bpmn2:scriptTask>
+    <bpmn2:sequenceFlow id="_43A53630-6A27-4E1C-AD13-F87924127544" drools:bgcolor="#000000" drools:selectable="true" sourceRef="_5A035F23-6CA6-4EC4-8EE5-A5E87B0B7C19" targetRef="_5C1B77ED-96D1-425C-921B-76F58B543385"/>
+    <bpmn2:scriptTask id="_1C194684-F81D-422A-9073-709E5AAD8398" drools:selectable="true" name="&scriptName2;" scriptFormat="http://www.java.com/java">
+      <bpmn2:incoming>_F4203272-5ED9-4E6D-9E23-4A992BA2E9F8</bpmn2:incoming>
+      <bpmn2:outgoing>_3541D5DD-E7BD-4F2F-8EA1-42D923FF1554</bpmn2:outgoing>
+      <bpmn2:script>&xxe1;</bpmn2:script>
+    </bpmn2:scriptTask>
+    <bpmn2:sequenceFlow id="_F4203272-5ED9-4E6D-9E23-4A992BA2E9F8" drools:bgcolor="#000000" drools:selectable="true" sourceRef="_5C1B77ED-96D1-425C-921B-76F58B543385" targetRef="_1C194684-F81D-422A-9073-709E5AAD8398"/>
+    <bpmn2:endEvent id="_F0EE04B3-79D8-40BC-8477-022A6CFE2C85" drools:bgcolor="#ff6347" drools:selectable="true" name="">
+      <bpmn2:incoming>_3541D5DD-E7BD-4F2F-8EA1-42D923FF1554</bpmn2:incoming>
+    </bpmn2:endEvent>
+    <bpmn2:sequenceFlow id="_3541D5DD-E7BD-4F2F-8EA1-42D923FF1554" drools:bgcolor="#000000" drools:selectable="true" sourceRef="_1C194684-F81D-422A-9073-709E5AAD8398" targetRef="_F0EE04B3-79D8-40BC-8477-022A6CFE2C85"/>
+  </bpmn2:process>
+  <bpmndi:BPMNDiagram id="_P4xkIV3VEeSfO7lCL83Qdw">
+    <bpmndi:BPMNPlane id="_P4xkIl3VEeSfO7lCL83Qdw" bpmnElement="async-examples.bp1">
+      <bpmndi:BPMNShape id="_P4yLMF3VEeSfO7lCL83Qdw" bpmnElement="_5A035F23-6CA6-4EC4-8EE5-A5E87B0B7C19">
+        <dc:Bounds height="30.0" width="30.0" x="122.0" y="165.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="_P4yLMV3VEeSfO7lCL83Qdw" bpmnElement="_5C1B77ED-96D1-425C-921B-76F58B543385">
+        <dc:Bounds height="80.0" width="100.0" x="180.0" y="140.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="_P4yLMl3VEeSfO7lCL83Qdw" bpmnElement="_43A53630-6A27-4E1C-AD13-F87924127544">
+        <di:waypoint xsi:type="dc:Point" x="137.0" y="180.0"/>
+        <di:waypoint xsi:type="dc:Point" x="230.0" y="180.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="_P4yLM13VEeSfO7lCL83Qdw" bpmnElement="_1C194684-F81D-422A-9073-709E5AAD8398">
+        <dc:Bounds height="80.0" width="100.0" x="325.0" y="140.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="_P4yLNF3VEeSfO7lCL83Qdw" bpmnElement="_F4203272-5ED9-4E6D-9E23-4A992BA2E9F8">
+        <di:waypoint xsi:type="dc:Point" x="230.0" y="180.0"/>
+        <di:waypoint xsi:type="dc:Point" x="375.0" y="180.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="_P4yLNV3VEeSfO7lCL83Qdw" bpmnElement="_F0EE04B3-79D8-40BC-8477-022A6CFE2C85">
+        <dc:Bounds height="28.0" width="28.0" x="469.0" y="165.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="_P4yLNl3VEeSfO7lCL83Qdw" bpmnElement="_3541D5DD-E7BD-4F2F-8EA1-42D923FF1554">
+        <di:waypoint xsi:type="dc:Point" x="375.0" y="180.0"/>
+        <di:waypoint xsi:type="dc:Point" x="483.0" y="179.0"/>
+      </bpmndi:BPMNEdge>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</bpmn2:definitions>

programming_language: HTML
filename: Text1.txt
change_type: ModificationType.ADD
diff: @@ -0,0 +1,2 @@
+System.out.println("Yikes! This script has been read from Text1.txt via an external entity.");
+kcontext.setVariable("testScript1", "XXE issue");
\ No newline at end of file

programming_language: SQL
filename: Text2.txt
change_type: ModificationType.ADD
diff: @@ -0,0 +1,2 @@
+System.out.println("Yikes! This script has been read from Text2.txt via an external entity.");
+kcontext.setVariable("testScript2", "XXE issue");
\ No newline at end of file

programming_language: SQL
filename: external.dtd
change_type: ModificationType.ADD
diff: @@ -0,0 +1,2 @@
+    <!ENTITY xxe2 SYSTEM "file:///Users/maciejswiderski/Development/git-repos/jbpm-main/jbpm-bpmn2/src/test/resources/xxe-protection/Text2.txt" >
+

programming_language: Batchfile
repo_url: https://github.com/droolsjbpm/drools
commit_details: repo_url: https://github.com/droolsjbpm/drools
author: Maciej Swiderski
author_date: 2014-12-22 14:17:52+01:00
msg: BZ-1169553 - (CVE-2014-8125) EMBARGOED CVE-2014-8125 jBPM: BPMN2 file processing XXE in Process Execution
repository: repo_url: https://github.com/droolsjbpm/drools
repo_name: apache/incubator-kie-drools
description: Drools is a rule engine, DMN engine and complex event processing (CEP) engine for Java.
repo_language: Java
owner: droolsjbpm
file_changes: filename: ExtensibleXmlParser.java
change_type: ModificationType.MODIFY
diff: @@ -223,7 +223,15 @@ public class ExtensibleXmlParser extends DefaultHandler {
                 throw new RuntimeException( "Unable to create new DOM Document",
                                             e );
             }
-            
+            // XXE protection start
+            try {
+                f.setFeature("http://xml.org/sax/features/external-general-entities", false);
+                f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+
+            } catch (ParserConfigurationException e) {
+                logger.warn("Unable to set parser features due to {}", e.getMessage());
+            }
+            // XXE protection end
             try {
                 this.document = f.newDocumentBuilder().newDocument();
             } catch ( Exception e ) {
@@ -254,6 +262,15 @@ public class ExtensibleXmlParser extends DefaultHandler {
             }
             
             factory.setNamespaceAware( true );
+            // XXE protection start
+            try {
+                factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
+                factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+
+            } catch (ParserConfigurationException e) {
+                logger.warn("Unable to set parser features due to {}", e.getMessage());
+            }
+            // XXE protection end
 
             final String isValidatingString = System.getProperty( "drools.schema.validating" );
             if ( System.getProperty( "drools.schema.validating" ) != null ) {

programming_language: Java