Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 195 additions & 0 deletions ci/tests/200-xslt-step-xxe/channels/01-xslt-xxe/channel.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
<channel version="4.6.0">
<id>5ec00001-0000-4000-8000-00000000c1a5</id>
<nextMetaDataId>2</nextMetaDataId>
<name>XSLT Step XXE</name>
<description></description>
<revision>1</revision>
<sourceConnector version="4.6.0">
<metaDataId>0</metaDataId>
<name>sourceConnector</name>
<properties class="com.mirth.connect.connectors.vm.VmReceiverProperties" version="4.6.0">
<pluginProperties/>
<sourceConnectorProperties version="4.6.0">
<responseVariable>None</responseVariable>
<respondAfterProcessing>true</respondAfterProcessing>
<processBatch>false</processBatch>
<firstResponse>false</firstResponse>
<processingThreads>1</processingThreads>
<resourceIds class="linked-hash-map">
<entry>
<string>Default Resource</string>
<string>[Default Resource]</string>
</entry>
</resourceIds>
<queueBufferSize>1000</queueBufferSize>
</sourceConnectorProperties>
</properties>
<transformer version="4.6.0">
<elements>
<com.mirth.connect.plugins.xsltstep.XsltStep version="4.6.0">
<name>XSLT XXE</name>
<sequenceNumber>0</sequenceNumber>
<enabled>true</enabled>
<sourceXml>connectorMessage.getRawData()</sourceXml>
<resultVariable>xsltResult</resultVariable>
<template>&apos;&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;&lt;xsl:output method=&quot;text&quot;/&gt;&lt;xsl:template match=&quot;/&quot;&gt;&lt;xsl:value-of select=&quot;.&quot;/&gt;&lt;/xsl:template&gt;&lt;/xsl:stylesheet&gt;&apos;</template>
<useCustomFactory>false</useCustomFactory>
<customFactory></customFactory>
</com.mirth.connect.plugins.xsltstep.XsltStep>
</elements>
<inboundDataType>RAW</inboundDataType>
<outboundDataType>RAW</outboundDataType>
<inboundProperties class="com.mirth.connect.plugins.datatypes.raw.RawDataTypeProperties" version="4.6.0">
<batchProperties class="com.mirth.connect.plugins.datatypes.raw.RawBatchProperties" version="4.6.0">
<splitType>JavaScript</splitType>
<batchScript></batchScript>
</batchProperties>
</inboundProperties>
<outboundProperties class="com.mirth.connect.plugins.datatypes.raw.RawDataTypeProperties" version="4.6.0">
<batchProperties class="com.mirth.connect.plugins.datatypes.raw.RawBatchProperties" version="4.6.0">
<splitType>JavaScript</splitType>
<batchScript></batchScript>
</batchProperties>
</outboundProperties>
</transformer>
<filter version="4.6.0">
<elements/>
</filter>
<transportName>Channel Reader</transportName>
<mode>SOURCE</mode>
<enabled>true</enabled>
<waitForPrevious>true</waitForPrevious>
</sourceConnector>
<destinationConnectors>
<connector version="4.6.0">
<metaDataId>1</metaDataId>
<name>Destination 1</name>
<properties class="com.mirth.connect.connectors.vm.VmDispatcherProperties" version="4.6.0">
<pluginProperties/>
<destinationConnectorProperties version="4.6.0">
<queueEnabled>false</queueEnabled>
<sendFirst>false</sendFirst>
<retryIntervalMillis>10000</retryIntervalMillis>
<regenerateTemplate>false</regenerateTemplate>
<retryCount>0</retryCount>
<rotate>false</rotate>
<includeFilterTransformer>false</includeFilterTransformer>
<threadCount>1</threadCount>
<threadAssignmentVariable></threadAssignmentVariable>
<validateResponse>false</validateResponse>
<resourceIds class="linked-hash-map">
<entry>
<string>Default Resource</string>
<string>[Default Resource]</string>
</entry>
</resourceIds>
<queueBufferSize>1000</queueBufferSize>
<reattachAttachments>true</reattachAttachments>
</destinationConnectorProperties>
<channelId>none</channelId>
<channelTemplate>${message.encodedData}</channelTemplate>
<mapVariables/>
</properties>
<transformer version="4.6.0">
<elements/>
<inboundDataType>RAW</inboundDataType>
<outboundDataType>RAW</outboundDataType>
<inboundProperties class="com.mirth.connect.plugins.datatypes.raw.RawDataTypeProperties" version="4.6.0">
<batchProperties class="com.mirth.connect.plugins.datatypes.raw.RawBatchProperties" version="4.6.0">
<splitType>JavaScript</splitType>
<batchScript></batchScript>
</batchProperties>
</inboundProperties>
<outboundProperties class="com.mirth.connect.plugins.datatypes.raw.RawDataTypeProperties" version="4.6.0">
<batchProperties class="com.mirth.connect.plugins.datatypes.raw.RawBatchProperties" version="4.6.0">
<splitType>JavaScript</splitType>
<batchScript></batchScript>
</batchProperties>
</outboundProperties>
</transformer>
<responseTransformer version="4.6.0">
<elements/>
<inboundDataType>RAW</inboundDataType>
<outboundDataType>RAW</outboundDataType>
<inboundProperties class="com.mirth.connect.plugins.datatypes.raw.RawDataTypeProperties" version="4.6.0">
<batchProperties class="com.mirth.connect.plugins.datatypes.raw.RawBatchProperties" version="4.6.0">
<splitType>JavaScript</splitType>
<batchScript></batchScript>
</batchProperties>
</inboundProperties>
<outboundProperties class="com.mirth.connect.plugins.datatypes.raw.RawDataTypeProperties" version="4.6.0">
<batchProperties class="com.mirth.connect.plugins.datatypes.raw.RawBatchProperties" version="4.6.0">
<splitType>JavaScript</splitType>
<batchScript></batchScript>
</batchProperties>
</outboundProperties>
</responseTransformer>
<filter version="4.6.0">
<elements/>
</filter>
<transportName>Channel Writer</transportName>
<mode>DESTINATION</mode>
<enabled>true</enabled>
<waitForPrevious>true</waitForPrevious>
</connector>
</destinationConnectors>
<preprocessingScript>// Modify the message variable below to pre process data
return message;</preprocessingScript>
<postprocessingScript>// This script executes once after a message has been processed
// Responses returned from here will be stored as &quot;Postprocessor&quot; in the response map
return;</postprocessingScript>
<deployScript>// This script executes once when the channel is deployed
// You only have access to the globalMap and globalChannelMap here to persist data
return;</deployScript>
<undeployScript>// This script executes once when the channel is undeployed
// You only have access to the globalMap and globalChannelMap here to persist data
return;</undeployScript>
<properties version="4.6.0">
<clearGlobalChannelMap>true</clearGlobalChannelMap>
<messageStorageMode>DEVELOPMENT</messageStorageMode>
<encryptData>false</encryptData>
<encryptAttachments>false</encryptAttachments>
<encryptCustomMetaData>false</encryptCustomMetaData>
<removeContentOnCompletion>false</removeContentOnCompletion>
<removeOnlyFilteredOnCompletion>false</removeOnlyFilteredOnCompletion>
<removeAttachmentsOnCompletion>false</removeAttachmentsOnCompletion>
<initialState>STARTED</initialState>
<storeAttachments>true</storeAttachments>
<metaDataColumns>
<metaDataColumn>
<name>SOURCE</name>
<type>STRING</type>
<mappingName>mirth_source</mappingName>
</metaDataColumn>
<metaDataColumn>
<name>TYPE</name>
<type>STRING</type>
<mappingName>mirth_type</mappingName>
</metaDataColumn>
</metaDataColumns>
<attachmentProperties version="4.6.0">
<type>None</type>
<properties/>
</attachmentProperties>
<resourceIds class="linked-hash-map">
<entry>
<string>Default Resource</string>
<string>[Default Resource]</string>
</entry>
</resourceIds>
</properties>
<exportData>
<metadata>
<enabled>true</enabled>
<lastModified>
<time>1775955953073</time>
<timezone>America/Chicago</timezone>
</lastModified>
<pruningSettings>
<archiveEnabled>true</archiveEnabled>
<pruneErroredMessages>false</pruneErroredMessages>
</pruningSettings>
<userId>1</userId>
</metadata>
</exportData>
</channel>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?xml version="1.0"?><!DOCTYPE r [<!ENTITY x SYSTEM "file:///etc/hostname">]><r>&x;</r>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ERROR
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?xml version="1.0"?><r>hello</r>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TRANSFORMED
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private String getTransformationScript() {
script.append("transformer = tFactory.newTransformer(new Packages.javax.xml.transform.stream.StreamSource(xsltTemplate));\n");
script.append("sourceVar = new Packages.java.io.StringReader(" + sourceXml + ");\n");
script.append("resultVar = new Packages.java.io.StringWriter();\n");
script.append("transformer.transform(new Packages.javax.xml.transform.stream.StreamSource(sourceVar), new Packages.javax.xml.transform.stream.StreamResult(resultVar));\n");
script.append("transformer.transform(Packages.com.mirth.connect.util.MirthXmlUtil.getSecureSource(sourceVar), new Packages.javax.xml.transform.stream.StreamResult(resultVar));\n");

return script.toString();
}
Expand Down
16 changes: 16 additions & 0 deletions server/src/main/java/com/mirth/connect/util/MirthXmlUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@

package com.mirth.connect.util;

import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Hashtable;

import javax.xml.XMLConstants;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
Expand All @@ -24,10 +26,12 @@
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.xml.sax.InputSource;

public class MirthXmlUtil {

Expand Down Expand Up @@ -114,6 +118,18 @@ public static String prettyPrint(String input) {
return input;
}

/** Returns a {@link Source} for XML from an untrusted origin. */
public static Source getSecureSource(Reader reader) throws Exception {
// Use newDefaultInstance to avoid whatever is on the classpath that might
// be poisoned from the channel classloader.
SAXParserFactory factory = SAXParserFactory.newDefaultInstance();
// False by default
factory.setNamespaceAware(true);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

return new SAXSource(factory.newSAXParser().getXMLReader(), new InputSource(reader));
}

public static String decode(String entity) {
if (entity.charAt(entity.length() - 1) == ';') // remove trailing
// semicolon
Expand Down
Loading
Loading