XXE and Java

XXE and Java

What is XXE

XXE (XML External Entity) is a fraudulent act that uses the XML external reference function to acquire (leak) the contents of a file inside the server or access a file on the internal network.

Since XXE may be expressed in applications that handle XML, care must be taken when handling XML documents.

Java and XML

To handle XML in Java, consider using javax.xml.parsers.DocumentBuilder. Be done.

Therefore, after that, you can reproduce it using javax.xml.parsers.DocumentBuilder. Let's think about countermeasures.

Conclusion

There is also a way to control the XXE basics link with JavaVM properties, so that may be the quickest way. On the other hand, if you are a Java programmer, it should not be difficult to create and control a resolver yourself.

Express XXE in Java

In the source code program below, the XML file is specified in the first argument and the operation mode of the external reference is specified in the second argument, so the XML file ([C: \ z \ xmlxxe] is the default operation mode. \ in1.xml](https://qiita.com/tomoki0sanaki/items/015b6e8b807ed256a6e4#xml%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB--in1xml)) I will read.

Like this.

xxe-java-defo.png

In the case of Java, it means that it will be attacked by XXE by default.

Make the xref object null

Next is [javax.xml.parsers.DocumentBuilder # setEntityResolver () method](https://docs.oracle.com/javase/jp/6/api/javax/xml/parsers/DocumentBuilder.html#setEntityResolver (org.xml) Try giving "NULL" in .sax.EntityResolver)).

Like this.

xxe-java-null.png

Unlike the .NET Framework, ** Null is the default resolver object, so in the case of Java, even NULL is subject to XXE attacks. ** **

Create your own xref object

Next is "** I want to use the external reference function in a limited way, but I want to prevent XXE ". Or, if you say " I want to prevent the external reference function by modifying the resolver **", you can make your own resolver.

That is, [javax.xml.parsers.DocumentBuilder # setEntityResolver () method](https://docs.oracle.com/javase/jp/6/api/javax/xml/parsers/DocumentBuilder.html#setEntityResolver (org.xml) .sax.EntityResolver))) has the first argument "org.xml.sax.EntityResolver Since it is an interface type, create your own class that inherits it and use it [javax.xml.parsers.DocumentBuilder # setEntityResolver () method](https://docs.oracle.com/javase/jp/6/api/ By assigning it to the first argument of javax / xml / parsers / DocumentBuilder.html # setEntityResolver (org.xml.sax.EntityResolver)), you can freely control the external reference.

The method that must be overwritten is "org.xml.sax.InputSource.InputSource resolveEntity (String publicId, String systemId) /EntityResolver.html#resolveEntity (java.lang.String,% 20java.lang.String)) "method only.

The key part of this is the String type that indicates the URL of the external reference in the second argument, so the corresponding "[org.xml.sax.InputSource.InputSource](https://docs.oracle.com/" javase / jp / 6 / api / org / xml / sax / InputSource.html) ”type is just returned.

And the appropriate from this "org.xml.sax.InputSource.InputSource" type "Java.io.InputStream" class or "[java.io.Reader](https:: //docs.oracle.com/javase/jp/6/api/java/io/Reader.html) ”class should be returned.

For example, individual customization is possible, such as requiring authentication or allowing only specific URIs.

The "exEntityResolver class" of the source code "exEntityResolver.java" is finally empty java.io.ByteArrayInputStream for systemId indicating all URIs. I decided to return the "exInputSource" class that only returns jp / 6 / api / java / io / ByteArrayInputStream.html).

It looks like this.

xxe-java-cust.png

Source code (XXEtest.java)

XXEtest.java


import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import java.io.File;
import org.xml.sax.EntityResolver;

public class XXEtest{
 public static void main(String args[]){
  System.out.println("java.exe test <<inFile>> <<Resolver>>");
  if(0 < args.length){
   Boolean IsResolve = false;
   exEntityResolver myExEntityResolver = null;
   if(1 < args.length){
    if(args[1].equals("null") == true){
     IsResolve = true;
    }else{
     myExEntityResolver = new exEntityResolver();
    }
   }
   try{
    DocumentBuilderFactory tempDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder tempDocumentBuilder = tempDocumentBuilderFactory.newDocumentBuilder();
    if(IsResolve == true){
     tempDocumentBuilder.setEntityResolver(null);
    }else if(myExEntityResolver != null){
     tempDocumentBuilder.setEntityResolver(myExEntityResolver);
    }
    Document tempDocument = tempDocumentBuilder.parse(new File(args[0]));
    System.out.println("getTextContent  : " + tempDocument.getTextContent());
    System.out.print("getXmlStandalone: ");
    tempDocument.setXmlStandalone(true);
    System.out.println(tempDocument.getXmlStandalone());
    System.out.println("========Detail=================");
    PrintNode(tempDocument.getChildNodes(), "");
   }catch(Exception e){
    e.printStackTrace();
   }
  }
 }
 static void PrintNode(NodeList nodeList, String spacer){
  Node node = null;
  for(int i=0; i< nodeList.getLength(); i++){
   node = nodeList.item(i);
   String typeStr = "unknown";
   switch(node.getNodeType()){
    case Node.ELEMENT_NODE:
     typeStr = "ELEMENT_NODE";
     break;
    case Node.ATTRIBUTE_NODE:
     typeStr = "ATTRIBUTE_NODE";
     break;
    case Node.TEXT_NODE:
     typeStr = "TEXT_NODE";
     break;
    case Node.CDATA_SECTION_NODE:
     typeStr = "CDATA_SECTION_NODE";
     break;
    case Node.ENTITY_REFERENCE_NODE:
     typeStr = "ENTITY_REFERENCE_NODE";
     break;
    case Node.ENTITY_NODE:
     typeStr = "ENTITY_NODE";
     break;
    case Node.PROCESSING_INSTRUCTION_NODE:
     typeStr = "PROCESSING_INSTRUCTION_NODE";
     break;
    case Node.COMMENT_NODE:
     typeStr = "COMMENT_NODE";
     break;
    case Node.DOCUMENT_NODE:
     typeStr = "DOCUMENT_NODE";
     break;
    case Node.DOCUMENT_TYPE_NODE:
     typeStr = "DOCUMENT_TYPE_NODE";
     break;
    case Node.NOTATION_NODE:
     typeStr = "NOTATION_NODE";
     break;
   }
   System.out.println(spacer + "name =" + node.getNodeName() + ", type=" + typeStr);
   System.out.println(spacer + "value=" + node.getNodeValue());
   System.out.println(spacer + "getTextContent=" + node.getTextContent());
   if(node.hasChildNodes() == true){
    PrintNode(node.getChildNodes(), spacer + " ");
   }
  }
 }
}

Source code (exEntityResolver.java)

A resolver that just returns an InputSource class that just returns an empty ByteArrayInputStream

exEntityResolver.java


import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.IOException;

public class exEntityResolver implements EntityResolver{
 public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException{
  System.out.println("publicId: " + publicId);
  System.out.println("systemId: " + systemId);
  return (InputSource)new exInputSource();
 }
}

Source code (exInputSource.java)

An InputSource class that just returns an empty ByteArrayInputStream.

exInputSource.java


import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.Reader;
import java.io.InputStreamReader;

public class exInputSource extends InputSource{
 ByteArrayInputStream myStream;
 public exInputSource(){
  byte[] hako = new byte[0];
  this.myStream = new ByteArrayInputStream(hako);
 }
 public InputStream getByteStream(){
  return (InputStream)this.myStream;
 }
 public Reader getCharacterStream(){
  return (Reader)new InputStreamReader(this.myStream);
 }
}

Return

Return to XXE basics

Recommended Posts

XXE and Java
Java and JavaScript
Getters and setters (Java)
[Java] Thread and Runnable
Java true and false
[Java] String comparison and && and ||
Java --Serialization and Deserialization
[Java] Arguments and parameters
timedatectl and Java TimeZone
[Java] Branch and repeat
[Java] Variables and types
java (classes and instances)
[Java] Overload and override
Study Java # 2 (\ mark and operator)
Java version 8 and later features
[Java] Difference between == and equals
[Java] Stack area and static area
[Java] Generics classes and generics methods
Java programming (variables and data)
Java encryption and decryption PDF
Java and Iterator Part 1 External Iterator
Java if and switch statements
Java class definition and instantiation
Apache Hadoop and Java 9 (Part 1)
[Java] About String and StringBuilder
[Java] HashCode and equals overrides
Java
☾ Java / Iterative statement and iterative control statement
Java methods and method overloads
java Generics T and? Difference
Advantages and disadvantages of Java
java (conditional branching and repetition)
About Java Packages and imports
Java
[Java] Upload images and base64
C # and Java Overrides Story
Java abstract methods and classes
Java while and for statements
Java encapsulation and getters and setters
About Java static and non-static methods
Differences between "beginner" Java and Kotlin
Use java with MSYS and Cygwin
Distributed tracing with OpenCensus and Java
[Java] Difference between Hashmap and HashTable
Java variable declaration, initialization, and types
Install Java and Tomcat with Ansible
AWS SDK for Java 1.11.x and 2.x
[Java] Basic types and instruction notes
Java release date and EOL summary
Java and first-class functions-beyond functional interfaces-
About fastqc of Biocontainers and Java
Java for beginners, expressions and operators 1
Java Primer Series (Variables and Types)
Encoding and Decoding example in Java
Basic data types and reference types (Java)
[Java] Loop processing and multiplication table
Java arguments, return values and overloads
OpenJDK 8 java and javac command help
Java reference mechanism (stack and heap)
Use JDBC with Java and Scala.
Java for beginners, expressions and operators 2