0x00 前提
Java 代码审计自学:主要自己一个人学习,有点闭门造车,搜索引擎学习法,但是还是记录一下,也分享一下,也便于将来的总结和反思,如果我能终能学到什么,我也会重新梳理思路,为那些自学者提供一个好的思路,所以有了下面的系列文章java代码审计自学篇。
0x01 XXE漏洞简介
XXE(XML外部实体注入,XML External Entity) ,在应用程序解析XML输入时,当允许引用外部实体时,可构造恶意内容,导致读取任意文件、探测内网端口、攻击内网网站、发起DoS拒绝服务攻击、执行系统命令等。Java中的XXE支持sun.net.www.protocol 里的所有协议:http,https,file,ftp,mailto,jar,netdoc。一般利用file协议读取文件,利用http协议探测内网,没有回显时可组合利用file协议和ftp协议来读取文件。
0x02 XXE相关基础概念
XML&DTD
XML (可扩展标记语言,EXtensible Markup Language),是一种标记语言,用来传输和存储数据,而非显示数据。
DTD(文档类型定义,Document Type Definition)的作用是定义 XML 文档的合法构建模块。它使用一系列的合法元素来定义文档结构。
实体ENTITY
XML中的实体类型,一般有下面几种:字符实体、命名实体(或内部实体)、外部普通实体、外部参数实体。除外部参数实体外,其它实体都以字符(&)开始,以字符(;)结束。
0x03 XXE审计函数
XML解析一般在导入配置、数据传输接口等场景可能会用到,涉及到XML文件处理的场景可查看XML解析器是否禁用外部实体,从而判断是否存在XXE。部分XML解析接口如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | javax.xml.parsers.DocumentBuilderFactory; javax.xml.parsers.SAXParser javax.xml.transform.TransformerFactory javax.xml.validation.Validator javax.xml.validation.SchemaFactory javax.xml.transform.sax.SAXTransformerFactory javax.xml.transform.sax.SAXSource org.xml.sax.XMLReader org.xml.sax.helpers.XMLReaderFactory org.dom4j.io.SAXReader org.jdom.input.SAXBuilder org.jdom2.input.SAXBuilder javax.xml.bind.Unmarshaller javax.xml.xpath.XpathExpression javax.xml.stream.XMLStreamReader org.apache.commons.digester3.Digester
   | 
 
0x04 漏洞代码例子
使用spring boot框架写的小例子
询问一个常用的解析方法,选择一个有回显的方法,方便学习
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
   |   @RequestMapping(value = "/DocumentBuilder", method = RequestMethod.POST)
    public String DocumentBuilderVuln(HttpServletRequest request) {       try {                      String body = WebUtils.getRequestBody(request); 				         	           DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();           DocumentBuilder db = dbf.newDocumentBuilder();         	         	           StringReader sr = new StringReader(body);           InputSource is = new InputSource(sr);         	         	           Document document = db.parse(is);                                StringBuilder buf = new StringBuilder();           NodeList rootNodeList = document.getChildNodes();           for (int i = 0; i < rootNodeList.getLength(); i++) {               Node rootNode = rootNodeList.item(i);               NodeList child = rootNode.getChildNodes();               for (int j = 0; j < child.getLength(); j++) {                   Node node = child.item(j);                   buf.append(String.format("%s: %s\n", node.getNodeName(), node.getTextContent()));               }           }           sr.close();         	           return buf.toString();       } catch (Exception e) {           logger.error(e.toString());           return EXCEPT;       }   
   | 
 
0x05 漏洞利用
http 协议探测
1 2 3 4 5
   | <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE joychou [     <!ENTITY xxe SYSTEM "http://127.0.0.1:8888"> ]> <root>&xxe;</root>
   | 
 
通过回显和延迟,粗略判断,或者DNS无回显探测

FILE 协议 任意文件读取
poc:
1 2 3 4 5
   | <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE joychou [     <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <root>&xxe;</root>
   | 
 
成功读取 etc/passwd

还有一些ooxml 这种后续再写其他的研究一下
0x06 修复
主要是这三句话,加入了禁止使用实体类
很多封装的方法,都是这样的去解决,都是禁用了ENTITY实体。
下面是DocumentBuilder禁用方法
1 2 3
   | dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);             dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);             dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | @RequestMapping(value = "/Sec", method = RequestMethod.POST)     public String DocumentBuilderSec(HttpServletRequest request) {         try {             String body = WebUtils.getRequestBody(request);             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();             dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);             dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);             dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);             DocumentBuilder db = dbf.newDocumentBuilder();             StringReader sr = new StringReader(body);             InputSource is = new InputSource(sr);             db.parse(is);               sr.close();         } catch (Exception e) {             logger.error(e.toString());             return EXCEPT;         }         return "DocumentBuilder security code";     }
   |