XXE in .Net and XPathDocument

Posted by on September 12, 2016

XXE, or XML External Entity, is an attack against applications that parse XML. It occurs when XML input contains a reference to an external entity that it wasn’t expected to have access to. Through this article, I will discuss how .Net handles XML for certain objects and how to properly configure these objects to block XXE attacks. It is important to understand that the different versions of the .Net framework handle this differently.

I will cover the XPathDocument object in this article. For details regarding XmlReader, XmlTextReader, and XmlDocument check out my original XXE and .Net article.

This article uses 2 files to demonstrate XXE which are described next.

Test.xml – This file is used as the test xml loaded into the application. It consists of the following:


<?xml version=”1.0″ ?>
<!DOCTYPE doc [<!ENTITY win SYSTEM “file:///C:/Users/user/Documents/testdata.txt”>]>
<doc>&win;</doc>

testData.txt – This file contains one simple string that we are attempting to import into our XML file: “This is test data for xml

XPathDocument

There are multiple ways to instantiate an XPathDocument object to parse XML. Lets take a look at a few of these methods.

Streams

You can create an XPathDocument by passing in a stream object. The following code snippet shows how this would look:

static void LoadXPathDocStream()
{
	string fileName = @"C:\Users\user\Documents\test.xml";

	StreamReader sr = new StreamReader(fileName);

	XPathDocument xmlDoc = new XPathDocument(sr);

	XPathNavigator nav = xmlDoc.CreateNavigator();

	Console.WriteLine("Stream: " + nav.InnerXml.ToString());
}

The code above then uses a XPathNavigator object to then read the data from the document. Previous to .Net 4.5.2, the code above is vulnerable to XXE by default. The following image shows there response when executed:

XXE 7

In .Net 4.5.2 and 4.6, this same call has been modified to be safe by default. The following image shows the same code targeting 4.5.2 and notice that the output no longer returns the test data.

XXE 8

File Path

Another option to load an XPathDocument is by passing in a path to the file. The following code snippet shows how this is done:

static void LoadXPathDocFile()
{
	string fileName = @"C:\Users\user\Documents\test.xml";

	XPathDocument xmlDoc = new XPathDocument(fileName);

	XPathNavigator nav = xmlDoc.CreateNavigator();

	Console.WriteLine("FilePath: " + nav.InnerXml.ToString());
}

In this example, the XPathDocument constructor takes a filename directly to access the xml. Just like the use of the stream above, in versions prior to 4.5.2, this is vulnerable by default. The following shows the output when targeting .Net 4.5.1:

XXE 9

In .Net 4.5.2 and 4.6, this same call has been modified to be safe by default. The following image shows the output is no longer returning the test data.

XXE 10

XmlReader

Ad mentioned above, XmlReader was covered in the previous post (https://www.jardinesoftware.net/2016/05/26/xxe-and-net/). I wanted to mention it here because just like in the previous post, the method is secure by default. The following example shows using an XmlReader to create the XPathDocument:

static void LoadXPathDocFromReader()
{
	string fileName = @"C:\Users\user\Documents\test.xml";

	XmlReader myReader = XmlReader.Create(fileName);
            
	XPathDocument xmlDoc = new XPathDocument(myReader);
	
	XPathNavigator nav = xmlDoc.CreateNavigator();

	Console.WriteLine("XmlReader: " + nav.InnerXml.ToString());
}

When executed, the reader defaults to not parsing DTDs and will throw an exception. This can be modified by setting the XMlReaderSettings to allow DTD parsing.

Wrap Up

Looking at the examples above, it appears the safest route is to use the XmlReader to create the XPathDocument. The other two methods are insecure by default (in versions 4.5.1 and earlier) and I didn’t see any easy way to make them secure by the properties they had available.

Comments

Comments are closed.