Friday, September 9, 2016

How To Defend against XXE Attack in .NET


How To Defend against External XML Entity Injection (XXE) Attack in .NET



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 point out the differences for each object.
I will cover the XmlReader, XmlTextReaderXMLDocument and XPathDocument. Here is a quick summary regarding the default settings:


XMLReader:

Prior to 4.0

The ProhibitDtd property is used to determine if a DTD will be parsed.
True (default) – throws an exception if a DTD is identified. (See Figure 1)
False – Allows parsing the DTD. (Potentially Vulnerable)
Code that throws an exception when a DTD is processed: – By default, ProhibitDtd is set to true and will throw an exception when an Entity is referenced.

static void Reader()
{
    string xml = "<?xml version=\"1.0\" ?><!DOCTYPE doc 
[<!ENTITY win SYSTEM \"file:///C:/Users/user/Documents/testdata2.txt\">]
><doc>&win;</doc>";

    XmlReader myReader = XmlReader.Create(new StringReader(xml));
            
    while (myReader.Read())
    {
        Console.WriteLine(myReader.Value);
    }
    Console.ReadLine();
}

Exception when executed:

Figure 1

Code that allows a DTD to be processed: – Using the XmlReaderSettings object, it is possible to allow the parsing of the entity. This could make your application vulnerable to XXE.

static void Reader()
{
    string xml = "<?xml version=\"1.0\" ?><!DOCTYPE doc 
[<!ENTITY win SYSTEM \"file:///C:/Users/user/Documents/testdata2.txt\">]
><doc>&win;</doc>";

    XmlReaderSettings rs = new XmlReaderSettings();

    rs.ProhibitDtd = false;

    XmlReader myReader = XmlReader.Create(new StringReader(xml),rs);
            
    while (myReader.Read())
    {
        Console.WriteLine(myReader.Value);
    }
    Console.ReadLine();
}

Output when executed showing injected text:

Figure 2
.Net 4.0+
In .Net 4.0, they made a change from using the ProhibitDtD property to the new DtdProcessing enumeration. There are now three (3) options:

  • Prohibit (default) – Throws an exception if a DTD is identified.
  • Ignore – Ignores any DTD specifications in the document, skipping over them and continues processing the document.
  • Parse – Will parse any DTD specifications in the document. (Potentially Vulnerable)

Code that throws an exception when a DTD is processed: – By default, the DtdProcessing is set to Prohibit, blocking any external entities and creating safe code.

static void Reader()
{
    string xml = "<?xml version=\"1.0\" ?><!DOCTYPE doc 
[<!ENTITY win SYSTEM \"file:///C:/Users/user/Documents/testdata2.txt\">]
><doc>&win;</doc>";

    XmlReader myReader = XmlReader.Create(new StringReader(xml));
            
    while (myReader.Read())
    {
        Console.WriteLine(myReader.Value);
    }
    Console.ReadLine();
}
Exception when executed:


Figure 3

                                                                            

Code that ignores DTDs and continues processing: – Using the XmlReaderSettings object, setting DtdProcessing to Ignore will skip processing any entities. In this case, it threw an exception because there was a reference to the entirety that was skipped.
static void Reader()
{
    string xml = "<?xml version=\"1.0\" ?><!DOCTYPE doc 
 [<!ENTITY win SYSTEM \"file:///C:/Users/user/Documents/testdata2.txt\">]
 ><doc>&win;</doc>";

    XmlReaderSettings rs = new XmlReaderSettings();
    rs.DtdProcessing = DtdProcessing.Ignore;

    XmlReader myReader = XmlReader.Create(new StringReader(xml),rs);
            
    while (myReader.Read())
    {
        Console.WriteLine(myReader.Value);
    }
    Console.ReadLine();
} 
Output when executed ignoring the DTD (Exception due to trying to use the unprocessed entity):                                               


 Figure 4


Code that allows a DTD to be processed: Using the XmlReaderSettings object, setting DtdProcessing to Parse will allow processing the entities. This potentially makes your code vulnerable.
static void Reader()
{
    string xml = "<?xml version=\"1.0\" ?><!DOCTYPE doc 
 [<!ENTITY win SYSTEM \"file:///C:/Users/user/Documents/testdata2.txt\">]
 ><doc>&win;</doc>";
   
    XmlReaderSettings rs = new XmlReaderSettings();
    rs.DtdProcessing = DtdProcessing.Parse;

    XmlReader myReader = XmlReader.Create(new StringReader(xml),rs);
            
    while (myReader.Read())
    {
        Console.WriteLine(myReader.Value);
    }
    Console.ReadLine();           
}
Output when executed showing injected text:
Figure 5


XMLTextReader:

The XmlTextReader uses the same properties as the XmlReader object, however there is one big difference. The XmlTextReader defaults to parsing XML Entities so you need to explicitly tell it not too.
Prior to 4.0
The ProhibitDtd property is used to determine if a DTD will be parsed.
  • True – throws an exception if a DTD is identified. (See Figure 1)
  • False (Default) – Allows parsing the DTD. (Potentially Vulnerable)
Code that allows a Dtd to be processed: (Potentially Vulnerable) – By default, the XMLTextReader sets the ProhibitDtd property to False, allowing entities to be parsed and the code to potentially be vulnerable.
static void TextReader()
{
    string xml = "<?xml version=\"1.0\" ?><!DOCTYPE doc 
 [<!ENTITY win SYSTEM \"file:///C:/Users/user/Documents/testdata2.txt\">]
 ><doc>&win;</doc>";

    XmlTextReader myReader = new XmlTextReader(new StringReader(xml));

    while (myReader.Read())
    {
         if (myReader.NodeType == XmlNodeType.Element)
         {
             Console.WriteLine(myReader.ReadElementContentAsString());
         }
    }
    Console.ReadLine();
}
Code that blocks the Dtd from being parsed and throws an exception: – Setting the ProhibitDtd property to true (explicitly) will block Dtds from being processed making the code safe from XXE. Notice how the XmlTextReader has the ProhibitDtd property directly, it doesn’t have to use the XmlReaderSettings object.

static void TextReader()
{
    string xml = "<?xml version=\"1.0\" ?><!DOCTYPE doc 
 [<!ENTITY win SYSTEM \"file:///C:/Users/user/Documents/testdata2.txt\">]
 ><doc>&win;</doc>";

    XmlTextReader myReader = new XmlTextReader(new StringReader(xml));

    myReader.ProhibitDtd = true;

    while (myReader.Read())
    {
       if (myReader.NodeType == XmlNodeType.Element)
       {
           Console.WriteLine(myReader.ReadElementContentAsString());
       }
    }
    Console.ReadLine();
}
4.0+
In .Net 4.0, they made a change from using the ProhibitDtD property to the new DtdProcessing enumeration. There are now three (3) options:
  • Prohibit – Throws an exception if a DTD is identified.
  • Ignore – Ignores any DTD specifications in the document, skipping over them and continues processing the document.
  • Parse (Default) – Will parse any DTD specifications in the document. (Potentially Vulnerable)
Code that allows a DTD to be processed: (Vulnerable) – By default, the XMLTextReader sets the DtdProcessing to Parse, making the code potentially vulnerable to XXE.
static void TextReader()
{
    string xml = "<?xml version=\"1.0\" ?><!DOCTYPE doc 
 [<!ENTITY win SYSTEM \"file:///C:/Users/user/Documents/testdata2.txt\">]
 ><doc>&win;</doc>";

    XmlTextReader myReader = new XmlTextReader(new StringReader(xml));

    while (myReader.Read())
    {
        if (myReader.NodeType == XmlNodeType.Element)
        {
            Console.WriteLine(myReader.ReadElementContentAsString());
        }
    }
    Console.ReadLine();
}
Code that blocks the Dtd from being parsed: – To block entities from being parsed, you must explicitly set the DtdProcessingproperty to Prohibit or Ignore. Note that this is set directly on the XmlTextReader and not through the XmlReaderSettings object.
static void TextReader()
{
    string xml = "<?xml version=\"1.0\" ?><!DOCTYPE doc 
 [<!ENTITY win SYSTEM \"file:///C:/Users/user/Documents/testdata2.txt\">]
 ><doc>&win;</doc>";

    XmlTextReader myReader = new XmlTextReader(new StringReader(xml));
   
    myReader.DtdProcessing = DtdProcessing.Prohibit;

    while (myReader.Read())
    {
         if (myReader.NodeType == XmlNodeType.Element)
         {
             Console.WriteLine(myReader.ReadElementContentAsString());
         }
    }
    Console.ReadLine();
}

Output when Dtd is prohibited:
Figure 6


XMLDocument:

For the XMLDocument, you need to change the default XMLResolver object to prohibit a Dtd from being parsed.
.Net 4.5 and Earlier
By default, the XMLDocument sets the URLResolver which will parse Dtds included in the XML document. To prohibit this, set the XmlResolver = null.
Code that does not set the XmlResolver properly (potentially vulnerable) – The default XMLResolver will parse entities, making the following code potentially vulnerable.
static void Load()
{
   string fileName = @"C:\Users\user\Documents\test.xml";

   XmlDocument xmlDoc = new XmlDocument();

   xmlDoc.Load(fileName);

   Console.WriteLine(xmlDoc.InnerText);

   Console.ReadLine();
}
Code that does set the XmlResolver to null, blocking any Dtds from executing: – To block entities from being parsed, you must explicitly set the XmlResolver to null. This example uses LoadXml instead of Load, but they both work the same in this case.
static void LoadXML()
{
   string xml = "<?xml version=\"1.0\" ?><!DOCTYPE doc 
 [<!ENTITY win SYSTEM \"file:///C:/Users/user/Documents/testdata2.txt\">]
 ><doc>&win;</doc>";

   XmlDocument xmlDoc = new XmlDocument();

   xmlDoc.XmlResolver = null;

   xmlDoc.LoadXml(xml);

   Console.WriteLine(xmlDoc.InnerText);

   Console.ReadLine();
}
.Net 4.6
It appears that in .Net 4.6, the XMLResolver is defaulted to Null, making the XmlDocument safe. However, you can still set the XmlResolver in a similar way as prior to 4.6 (see previous code snippet).

XPathDocument:


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

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:

Figure 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.

Figure 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:
Figure 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.

Figure 10

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.

About Author:


I'm Mohamed M.Fouad Senior Information Security Engineer / Consultant at SecureMisr also an Independent Security Researcher from Egypt with more than 8 years of experience in web and mobile applications development, penetration testing, secure-coding, Network penetration testing, security code auditing and incident response. Conducted vulnerability assessment and penetration testing for many high-profiles companies and banks over all middle east. In addition to worked as a free-lancer with multi-national companies ex: Monster Recruitment...

I have been got acknowledgement from many of the Firms like as :
Microsoft,Oracle,Yahoo,Google,eBay,Sony,WordPress,ESET,BitDefender,AT&T,Huawui,DropCam, Bitcasa, Get Pocket, Splitwise and so many...

Certificates:  CRTP | OSWP | OSCP | GWAPT | CEH | MCPD | MCTS



4 comments:

  1. Very nice post here thanks for it .I always like and such a super contents of these post.Excellent and very cool idea and great content of different kinds of the valuable information's.
    uber driver promo code

    ReplyDelete
  2. I really loved reading your thoughts, obviously you know what are you talking about! Your site is so easy to use too, I’ve bookmark it in my folder
    Uber New Driver Promo Code

    ReplyDelete
  3. I tried to run some of your code examples in .net framework 4.5.2. In my case I got XmlException "Unexpected DTD declaration" in both cases when it is expected as default behavior or with setting DtdProcessing.Ignore.

    ReplyDelete