...
This noncompliant code example attempts to parse the file evil.xml
, report any errors, and exit. However, a SAX (Simple API for XML) or a DOM (Document Object Model) parser will attempt to access the URI specified by the SYSTEM
attribute, which means it will attempt to read the contents of the local /dev/tty
file. On POSIX systems, reading this file causes the program to block until input data is supplied to the machine's console. Consequently, an attacker can use this malicious XML file to cause the program to hang.
Code Block | ||
---|---|---|
| ||
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; class XXE { private static void receiveXMLStream(InputStream inStream, DefaultHandler defaultHandler) throws ParserConfigurationException, SAXException, IOException { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser saxParser = factory.newSAXParser(); saxParser.parse(inStream, defaultHandler); } public static void main(String[] args) throws ParserConfigurationException, throws ParserConfigurationException, SAXException, IOException { try { receiveXMLStream(new FileInputStream("evil.xml"), new DefaultHandler()); } catch (java.net.MalformedURLException mue) { System.err.println("Malformed URL Exception: " + mue); new DefaultHandler());} } } |
This program is subject to a remote XXE attack if the evil.xml
file contains the following:
Code Block | ||
---|---|---|
| ||
<?xml version="1.0"?> <!DOCTYPE foo SYSTEM "file:/dev/tty"> <foo>bar</foo> |
...
Compliant Solution (EntityResolver
)
...
Code Block | ||
---|---|---|
| ||
import java.io.IOException; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; class CustomResolver implements EntityResolver { public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { // Check for known good entities String entityPath = "file:/homeUsers/username/java/xxe/fileonlinestore/good.xml"; if (systemId.equals(entityPath)) { System.out.println("Resolving entity: " + publicId + " " + systemId); return new InputSource(entityPath); } else { // Disallow unknown entities by returning a blank path return new InputSource(); } } } |
The setEntityResolver()
method registers the instance with the corresponding SAX driver. When parsing malicious input, the empty InputSource
returned by the custom resolver causes a java.net.MalformedURLException
to be thrown. Note that you must create an XMLReader
object on which to set the custom entity resolver.
Code Block | ||
---|---|---|
| ||
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; class XXE { private static void receiveXMLStream(InputStream inStream, DefaultHandler defaultHandler) throws ParserConfigurationException, throws ParserConfigurationException, SAXException, IOException { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser saxParser = factory.newSAXParser(); // Create an XML reader to set the entity resolver. XMLReader reader = saxParser.getXMLReader(); reader.setEntityResolver(new CustomResolver()); reader.setContentHandler(defaultHandler); InputSource is = new InputSource(inStream); reader.parse(is); } public static void main(String[] args) throws ParserConfigurationException, throws ParserConfigurationException, SAXException, IOException { try { receiveXMLStream(new FileInputStream("evil.xml"), new DefaultHandler()); } catch (java.net.MalformedURLException mue) { System.err.println("Malformed URL Exception: " + mue); new DefaultHandler());} } } |
Risk Assessment
Failure to sanitize user input before processing or storing it can result in injection attacks.
...