XXE漏洞那些事儿(JAVA)
0x01 前言
之前我们学习了DocumentBuilder这个XML解析类的使用方法,还展示了如何读取本地文件以及利用XXE外带数据,当然,也简单的提到了相应的防御方法,这一章,我们将学习其他一些JAVA中常用的XML解析方法以及编码规范
0x02 javax.xml.parsers.SAXParser
使用方法如下:
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
File file = new File("payload.xml");
SaxHandler handler = new SaxHandler();
parser.parse(file, handler);
}
}
其中payload.xml还是上一章的那个xml文件,值得注意的的是,SaxParser在调用parse方法的时候有两个参数,其中一个是文件,另外一个是对应的handler,这个handler是我们自定义的,实现如下:
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SaxHandler extends DefaultHandler {
@Override
public void startDocument() throws SAXException {
super.startDocument();
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
}
// 此方法有三个参数
// arg0是传回来的字符数组,其包含元素内容
// arg1和arg2分别是数组的开始位置和结束位置
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String content = new String(ch, start, length);
System.out.println(content);
super.characters(ch, start, length);
}
}
该类继承自DefaultHandler,然后重写了几个比较关键的方法,当然不充些也是ok的,根据这些方法名大家应该能猜出这些方法的作用,比如startDocument这个方法,作用是当解析到xml文档开始处会执行这个方法,startElement就是解析到xml的Element开始处会被触发。这些方法都是自由定制的,可发挥空间很大~
运行主类,控制到得到如下结果,成果读取到本地文件win.ini,说明XXE成功。
0x03 org.dom4j.io.SAXReader
这是一个第三方的类,我们需要下载对应的jar包:
https://dom4j.github.io/
使用方法:
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.xml.parsers.SAXParser;
import java.io.File;
import java.util.List;
public class Main2 {
public static void main(String[] args) throws DocumentException {
File file = new File("./payload.xml");
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(file);
// 获得根元素
Element root = document.getRootElement();
// 获得根元素中的子元素
List<Element> childs = root.elements();
// 遍历子元素,并打印出对应的键值
for (Element child:childs){
String name = child.getName();
String text = child.getText();
System.out.println(name + ": " + text);
}
}
}
0x04 org.jdom2.input.SAXBuilder
同样是第三方类,下载jar包:
http://www.jdom.org/dist/binary/jdom-2.0.6.zip
使用方法:
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class Main3 {
public static void main(String[] args) throws JDOMException, IOException {
File file = new File("./payload.xml");
SAXBuilder saxBuilder = new SAXBuilder();
Document document = saxBuilder.build(file);
Element root = document.getRootElement();
List<Element> childs = root.getChildren();
for(Element child:childs){
String name = child.getName();
String text = child.getText();
System.out.println(name+": "+text);
}
}
}
0x05 小结
其实能够解析xml的类库还有很多,这里只是列举了几个,更多可以参考:
https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.md
知道了这些类怎么解析xml,我们在审计的时候就可以搜索对应的jar包,然后进一步看xml解析的类有没有被调用,被调用了然后再看对应的接口参数是否可控,如果可控还要观察这些解析类有没有相应的防御措施,比如禁用了外部实体等等,关于XXE的防御,往下看吧....
0x06 防御手法
我在《XXE之DocumentBuilder》文末蜻蜓点水般提到了XXE的防御方法,这会,我们详细来说说,由于java中各个xml解析类防御xxe的方法都大同小异,我就那SAXReader来演示吧
要想完全防御住xxe攻击,需要设置以下三个属性,如果遗漏了其中一个,应用都是有可能受到XXE攻击的,只是说危害程度不同
saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
saxReader.setFeature("http://xml.org/sax/features/external-general-entities", false);
saxReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
那么每个特性都是啥意思呢,又有啥用呢,大家可以仔细阅读一下每个特性的名字,可以猜到个大概。
disallow-doctype-decl
看名字,就是不允许文档类型声明(不允许定义Doctype),将这个特性设置为true后,基本可以防御大部分xxe攻击,我们看设置过后的效果
直接报错,从报错中可以看到设置了该属性后就不能在xml文件中声明Doctype了,xml文件还是《XXE之DocumentBuilder》中的哪个payload.xml,这里就不列出来了
external-general-entities
这个特性看名字就是与外部普通实体挂钩的啦。当把这个特性设置为false,xml出现外部普通实体就是不会解析的,为了更好的观察,我们改一下xml文件,改成这样:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE root [
<!ENTITY test SYSTEM "http://localhost:8000/123.txt">
]>
<person>
<name>axin</name>
<age>&test;</age>
</person>
然后用python快速搭建一个http server:
python -m SimpleHTTPServer
我们看一下当我们把特性external-general-entities设置为false时会是怎样的结果:
可见,果然没有解析外部实体,http server都没有收到任何请求,但是在这种情况下,还是可以使用外部参数实体的
external-parameter-entities
当这个特性设置为false, 将会禁用外部参数实体, 而不会禁止普通实体,关于XXE漏洞以及XML文件的基础知识我这里暂且不谈,欲进一步了解移步:https://thief.one/2017/06/20/1/
我们先用普通的外部实体测试一下,可见能够正常解析,如下:
然后,修改一下xml文件,改用参数实体:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE root [
<!ENTITY % test SYSTEM "http://localhost:8000/123.txt">
%test;
]>
<person>
<name>axin</name>
<age>age</age>
</person>
如果正常解析的话,http server是应该能够收到请求的,但是结果如下:
可见确实解析不了外部参数实体了...
0x07 其他
更详细的防御手册:https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.md
虽然,针对不同类的防御方法有些许出入,但是核心不变,所以,你今天掌握了核心科技了吗~
拓展阅读:
https://www.leadroyal.cn/?p=562
https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.md
- Linux64位程序移植
- history命令使用方法详解
- Linux删除乱码文件的方法
- 和智能机器一起工作,而不是惧怕它们
- Hulu大数据架构与应用经验
- SQL Server 2005:一个使用新创建的User的问题和解决方法
- Audit Logging-Stored Procedure
- Linux进程间通信(四) - 共享内存
- 扩展UltraGrid控件实现对所有数据行的全选功能[Source Code下载]
- Linux进程间通信(一) - 管道
- Linux进程间通信(二) - 消息队列
- Linux进程间通信(三) - 信号
- 我的WCF之旅(7):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的继承
- Linux进程间通信(IPC)机制总览
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- OpenCV与图像处理(四)
- 常用功能加载宏——单元格数据连接
- Nest.js 从零到壹系列(八):使用 Redis 实现登录挤出功能
- 创建常用功能加载宏
- 3分钟短文 | Linux 使用curl发起post请求的4个常用方式
- 类模块——接口
- OpenCV与图像处理(三)
- 常用功能加载宏——单元格数字转变
- OpenCV与图像处理(二)
- ECCV2020 | SOD100K:超低参数量的高效显著性目标检测算法,广义OctConv和动态权重衰减
- Rust FFI 编程 - Rust导出共享库02
- 常用功能加载宏——单元格数字格式
- 【翻译】200行代码讲透RUST FUTURES (2)
- 【Rust日报】2020-07-23 Rust 的 CI 将使用 GitHub Actions
- 【每周一库】- Tonic 基于Rust的gRPC实现