使用Java的XXE
XXE和Java
XXE是什么指的是什么?
XXE(XML外部实体)是利用XML的外部引用功能来获取(泄露)服务器内部文件内容,或者访问内部网络中的文件进行非法行为的。
由于XXE(XML外部实体)可能在处理XML的应用程序中出现,所以在处理XML文档时需要注意。
Java 和 XML
要在Java中处理XML,可以考虑使用javax.xml.parsers.DocumentBuilder。
因此,接下来,我们可以尝试使用javax.xml.parsers.DocumentBuilder来重现或思考解决方案。
結果
在XXE基本編的链接中,也可以通过JavaVM的属性来控制,因此可以选择快捷的方式。但另一方面,作为Java程序员,自己编写解析器并进行控制也应该不是很困难。
使用Java触发XXE漏洞
请尝试使用以下的答案:
下面的源代码程序中,第一个参数要指定XML文件,第二个参数要指定外部引用的操作模式,所以我们可以使用默认的操作模式,读取XML文件(C:\z\xmlxxe\in1.xml)。
就是这样的感觉。
在Java的情况下,通常会受到XXE攻击。
将外部参考对象设置为NULL
下面我们尝试使用javax.xml.parsers.DocumentBuilder#setEntityResolver()方法并传入“NULL”。
差不多这样的感觉。
与.NET Framework不同,Java中的Null被视为默认的解析器对象,因此即使是NULL,在Java的情况下也可能受到XXE攻击的影响。
自己制作外部参考对象
如果想要有限地使用外部引用功能但又想避免XXE,在需要修改解析器来防止外部引用功能的情况下,可以自行编写解析器。
换句话说,javax.xml.parsers.DocumentBuilder#setEntityResolver()方法的第一个参数是”org.xml.sax.EntityResolver”接口类型,因此可以自定义继承该接口的类,并将其分配给javax.xml.parsers.DocumentBuilder#setEntityResolver()方法的第一个参数,从而可以自由地控制外部引用。
必須覆写的方法只有一个:”org.xml.sax.InputSource.InputSource resolveEntity(String publicId,String systemId)”方法。
这里关键的部分是,第二个参数是一个String类型,用于指示外部引用的URL,所以只需要返回相应的”org.xml.sax.InputSource.InputSource”类型即可。
然后,只需要确保从该”org.xml.sax.InputSource.InputSource”类型正确返回”java.io.InputStream”类或”java.io.Reader”类即可。
例如,可以进行个别定制,如需要验证或仅允许特定的URI。
在源代码文件”exEntityResolver.java”的exEntityResolver类中,决定对于表示所有URI的systemId,最终返回一个空的java.io.ByteArrayInputStream的exInputSource类。
变成这样的感觉。
源代码(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 + " ");
}
}
}
}
源代码(exEntityResolver.java)
返回一个仅返回空的 ByteArrayInputStream 的 InputSource 类的解析器。
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();
}
}
源代码(exInputSource.java)
只返回一个空的 ByteArrayInputStream 的 InputSource 类。
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);
}
}
返回
返回到基本编辑栏