Ⅰ xmldecoder反序列化漏洞分析
java提供了很多xml文档解析的类库,包括dom4j,domj,SAX等库,可以进行xml文档的解析,这些库的使用不当,会导致XXE漏洞的发生,但是这些类库中,SAX库允许自己去定义整个xml文档处理的handler,可以在xml文档解析的过程中,对解析出来的节点进行一些操作
而为java反序列化定义的handler,会导致一些java反序列化的问题的发生
poc:
获取到文件内容之后,用XMLDecoder解析,在下面调用了readObject方法
进入readObject方法中
这里对文档进行了解析,而XMLDecoder.this.handler其实就是
DocumentHandler
这个handler很重要,所有反序列化的操作都是在这个类中进行的
之类通过SAXParserFactory实例化了一个SAXParser的实例,并且调用了其中的parse方法
复现过java XXE漏洞的师傅应该看见过SAXParser的用法,它允许用户自己去定义处理文档的handler
可以看到,用户可以将自己定义的Handler,只要这个类继承了DefaultHandler,可以看一下官网的例子:
自己的Handler可以在解析的不同阶段,进行不同的操作,这个特点就让xml文档成为了可以进行java序列化的载体,DocumentHandler这个handler就是处理xml文档反序列化的
接下来,调用SAXParser对xml文档进行解析,在对一些属性的设置以后,真正的解析流程在XML11Configuration这个类中的parse方法中开始
首先是对实体的解析:
因为我们的文档中并没有xml实体,所以这一步不用关注
之后进行文档的解析
进入到scanDocument函数中
这里通过next函数,解析了文档,并且返回当前解析的状态,整个文档的具体解析过程在这个类的ContentDriver类中,里面的解析过程很复杂,具体的解析过程不要过于关注,重点在解析出来的结果的处理上
当发现当前的文档为根节点的时候,调用fContentDriver的next方法,在这里进行ROOT节点的解析
一直到的scanStartElement方法中
在之类对文档进行解析,调用scanName解析出来第一个节点名为:java
之后寻找java节点的结束字符在哪,并且解析出来中间的所有属性
在解析结束以后,会将这个节点中的所有属性添加到fAttributes中
最后来到startElement函数中,可以认为fElementQName就是我们的节点名称,fAttributes就是这个节点中所有属性组成的一个字典
最后调用到DocumentHandler的startElement才到真正反序列化的地方
到这里,一个节点的解析就算结束了,头都看大了,先附上一张调用栈,再到DocumentHandler中看具体的反序列化过程
在最后,调用了DocumentHandler.startElement函数,我们进入看一下
在这里会根据不同的节点实例化不同的节点Handler
this.handlers中寻找java节点对应的handler,可以看一下this.handlers里面所有的handler都是什么,它是一个HashMap,在属性中有定义 private final Map<String, Class<? extends ElementHandler>> handlers = new HashMap();
在构造方法中,对handlers进行了赋值
这也就是XMLDecoder所有支持的节点类型,不同的节点会调用不同的ElementHandler进行处理,我们的java节点,应该是被JavaElementHandler处理的
回到startElement的方法中
在实例化JavaElementHandler类以后,调用了setParent将上一次的handler保存,这一步相当于将每一个节点的处理类串成了一个链
这一步获取到所有的节点属性,并且调用处理handler自己实现的addAttribute方法,可以看一下JavaElementHandler的addAttribute
这里通过我们设置的class属性的内容,获取了对应的类,也就是java.beans.XMLDecoder类的class
之后调用对应handler的startElement,而java的handler没有操作,所以进行下一个节点的解析
下一个节点是object,具体解析流程就不再分析
object对应的Handler为ObjectElementHandler,可以发现,startElement中的重点其实就是每个Handler的addAttribute方法和startElement方法
调用父类的addAttribute方法
这一步获得了ProcessBuilder的class
处理handler:ArrayElementHandler
addAttribute:
这里定义了数组元素的类型和数组大小
startElement:
这里实例化了一个数组元素,并且返回了一个ValueObject对象
void节点比较特殊,void节点其实是object节点的一个子类,它本身没有定义什么方法
我们可以不用过多的关注void节点的处理规则,只需要理解它的作用就是声明一个变量就可以,可以这么理解:
在一个节点处理结束以后,会由内向外依次调用每个节点的endElement方法
比如我们的poc
在解析完touch的string节点的之后,触发string的endElement,主要就是将将值设置为StringElementHandler的属性
之后向ArrayElementHandler中的数组添加进去这个String,对每个element都会调用getValueObject方法,而其中
void节点的endElement很有意思
看一下getContextBean方法
这里会获取上一个Handler的ValueObject的值,而这个ValueObject的value就是我们在属性中定义的对象,void节点的上一个节点是array节点,我们在array节点中定义了一个大小为2的String数组,所以获取到的ValueObject就为这个数组
因为我们只设置了void的属性为index="0",所以会进入到var4=set的条件中
最后的Express类,相当于是对var3这个对象调用其中的var4的方法,参数为var2,这样,就为这个String数组赋值了第一个值为touch
来到第二个void标签
当来到 <void method="start"/>
进入到getContextBean
在这里调用了parent的getValueObject方法,也就是object标签
获取了ObjectElementHandler中的ProcessBuilder对象
最后调用start执行命令
Ⅱ 如何把xml内容转换为java格式
使用XStream完成 java 类与 XML 互换。
下面代码实现了以下种基本功能:
1. object类型转换为xml类型,在控制台打印
2. xml类型转换为object类型,在控制台打印
3. 将object类型转换为xml类型,并写入XML文件
4. 读取XML文件,加载进相应Object类型
====================================================
1。加载 XStream 需要的jar包 xstream-1.4.2.jar
xpp3_min-1.1.4c.jar
xmlpull-1.1.3.1.jar
2。创建实体类User.java
package com.entity;
/**
* 实体类
*/
public class User {
private String userName;
private String password;
private String registeredTime;
public User() { }
public User(String userName, String passWord, String registeredTime) {
this.userName = userName;
this.passWord = passWord;
this.registeredTime = registeredTime;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public String getRegisteredTime() {
return registeredTime;
}
public void setRegisteredTime(String registeredTime) {
this.registeredTime = registeredTime;
}
}
3。编写功能实现类
package com.switcher;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.entity.User;
import com.thoughtworks.xstream.XStream;
/**
*
* 使用 XStream不用任何映射就能实现多数 Java 对象的序列化。
* 在生成的 XML中对象名变成了元素名,类中的字符串组成了 XML中的元素内容。
* 使用 XStream 序列化的类不需要实现 Serializable 接口。
* XStream 是一种序列化工具而不是数据绑定工具
* 不能从XML 或者 XML Schema Definition (XSD) 文件生成类。
*/
public class SwitchXML {
/*
* XStream 不关心序列化/逆序列化的类的字段的可见性。
* 序列化/逆序列化类的字段不需要 getter 和 setter 方法。
* 序列化/逆序列化的类不需要有默认构造函数。
*/
private XStream xStream = new XStream();
private String xmlPath = "D:/userdata.xml";
// 1. obj -> xml(object类型转换为xml类型)
public String printXML(User user) {
System.out.println("obj -> xml");
String xml = xStream.toXML(user);
System.out.println(xml);
return xml;
}
// 2. xml->obj(xml类型转换为object类型,并打印)
public void printObj(String xml) {
System.out.println("xml -> obj");
User u = (User) xStream.fromXML(xml);
System.out.println(u.getUserName() + " " + u.getPassWord() + " " + u.getRegisteredTime());
}
// 3. 将object类型转换为xml类型,并写入XML文件(其他格式也可以,比如txt文件)
public void writerXML(User user) {
try {
FileOutputStream fs = new FileOutputStream(xmlPath);
xStream.toXML(user, fs);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
// 4. 读取XML文件,加载进相应Object类型
public void readerXML() {
User user = new User();
FileInputStream fis = null;
try {
fis = new FileInputStream(xmlPath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
xStream.fromXML(fis, user);
// 打印对象信息
System.out.println(user.toString());
// 打印对象的属性值
System.out.println(user.getUserName() + "-" + user.getPassWord() + "-"
+ user.getRegisteredTime());
}
public static void main(String[] args) {
// 用户名
String username = "admin";
// 密码
String password = "admin";
// 注册时间
Date now = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
String registeredtime = format.format(now);
User user = new User(username, password, registeredtime);
SwitchXML switchXML = new SwitchXML();
// 1. object类型转换为xml类型,在控制台打印
String xml = switchXML.printXML(user);
System.out.println("---------------------");
// 2. xml类型转换为object类型,在控制台打印
switchXML.printObj(xml);
System.out.println("---------------------");
// 3. 将object类型转换为xml类型,并写入XML文件
switchXML.writerXML(user);
System.out.println("---------------------");
// 4. 读取XML文件,加载进相应Object类型
switchXML.readerXML();
}
}
Ⅲ Java程序员常用的开发工具有哪些
在当今的互联网时代中,Java语言越来越流行。关于Java的一些常用工具也需要我们不断的掌握和理解。下面云南java培训为大家介绍,Java程序员常用的开发工具有哪些。
一、ServiceLoader-加载服务
Java开发人员通常希望区分使用什么和创建什么,昆明java课程培训机构发现通常是通过创建一个描述组件操作的接口和使用某种中介创建组件实例。
二、SCanner
无数的Java开发工具可以帮助您构建解析器,许多函数语言已经成功地构建解析器库(解析器选择器)。但是,如果您想解析逗号分隔的值蠢斗文件或空格分隔的文本文件呢?云南java课程发现大多数工具都太大了,不能在这里使用,String.split()是不够的。
三、Timer
Java.util.Timer和TimerTask类提供了一种方便且相对简单的基于周期性或临时延迟执行任务的方法。
四、StAX-解析XML文件
当许多Java开发人员首次使用XML时,分析XML文件的基本方法有两种。云南昆明IT培训认为SAX解析器实际上是一个大型状态机,程序员对事件调用一系列回调方法。DOM分析程序将整个XML文敏档郑档添加到内存中,分离并分割成各个对象,并将它们连接起来形成桥颂树。