本文首发自https://www.secpulse.com/archives/95012.html,转载请注明出处。html
Java 提供了一种对象序列化的机制,该机制中,一个对象能够被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。反序列化就是经过序列化后的字段还原成这个对象自己。但标识不被序列化的字段是不会被还原的。java
1)网站相应的session对象存储在硬盘上,那么保存在session中的内容就必须实现相关的序列化操做。git
2)若是使用的java对象要在分布式中使用或者在rmi远程调用的网络中使用的话,那么相关的对象必须实现java序列化接口。github
咱们最多见就是原生的java反序列化类型,其实java中有几种方式能够执行反序列化,本文目的也是对这几种类型的反序列化方法进行概括和总结。apache
Java包中自带的类InputStream和OutputStream,它们之间能够互相转化,使用writeObject序列化,使用readObject反序列化。json
import java.io.*; public class DeserializeDemo { public static void main(String [] args) { Employee e = null; try { FileInputStream fileIn = new FileInputStream("/tmp/employee.ser"); ObjectInputStream in = new ObjectInputStream(fileIn); e = (Employee) in.readObject(); in.close(); fileIn.close(); }catch(IOException i) { i.printStackTrace(); return; }catch(ClassNotFoundException c) { System.out.println("Employee class not found"); c.printStackTrace(); return; } System.out.println("Deserialized Employee..."); System.out.println("Name: " + e.name); System.out.println("Address: " + e.address); System.out.println("SSN: " + e.SSN); System.out.println("Number: " + e.number); } }
Json序列化通常会使用jackson包,经过ObjectMapper类来进行一些操做,好比将对象转化为byte数组或者将json串转化为对象。数组
public static <T> String serialize(T t) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String jsonResult = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(t);
return jsonResult;
}
Fastjson是一个性能很好的Java语言实现的Json解析器和生成器,由来自阿里巴巴的工程师开发。具备极快的性能,超越任何其余的Java Json Parser。Fastjson使用parseObject来进行反序列化。网络
import com.alibaba.fastjson.JSON;
public class Person {
int age;
String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
String jsonString="{\"name\":\"hah\",\"age\":1}";
Person person = JSON.parseObject(jsonString, Person.class);
System.out.println(1);
}
}
Protocol Buffers 是一种轻便高效的结构化数据存储格式,能够用于结构化数据串行化,或者说序列化。它很适合作数据存储或 RPC 数据交换格式。可用于通信协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。session
proto.proto文件内容数据结构
package proto; message TestMsg{ optional string id = 1; optional string name = 2; }
序列化
public byte[] build(){ Proto.TestMsg.Builder builder = Proto.TestMsg.newBuilder(); builder.setId("ID的值"); builder.setName("Name的值"); Proto.TestMsg msg = builder.build(); return msg.toByteArray(); }
反序列化
Proto.TestMsg msg = Proto.TestMsg.parseFrom(message.returnByte()); System.out.Println(msg);
除了使用protobuf进行反序列化没有出现过漏洞,其余方式的序列化都曾出现过漏洞。下面将简单介绍下漏洞,详细的漏洞和exp构造方法你们能够去网上搜索关键字查看(java几个反序列化漏洞exp构造过程都十分精彩,推荐你们认真阅读下)
Apache Commons Collections中实现了TransformedMap ,该类能够在一个元素被添加/删除/或是被修改时(即key或value:集合中的数据存储形式便是一个索引对应一个值,就像身份证与人的关系那样),会调用transform方法自动进行特定的修饰变换。
TransformedMap.decorate方法,预期是对Map类的数据结构进行转化,该方法有三个参数。
经过对第三个参数经过构造ChainedTransformer链,经过一系列变化,最终执行系统命令。
Jackson是一套开源的java序列化与反序列化工具框架,可将java对象序列化为xml和json格式的字符串及提供对应的反序列化过程。因为其解析效率较高,目前是Spring MVC中内置使用的解析方式,该漏洞的触发条件是ObjectMapper反序列化前调用了enableDefaultTyping方法。该方法容许json字符串中指定反序列化java对象的类名,而在使用Object、Map、List等对象时,可诱发反序列化漏洞,致使可执行任意命令。
fastjson在解析json的过程当中,支持使用autoType来实例化某一个具体的类,并经过json来填充其属性值。而JDK自带的类com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl中有一个私有属性_bytecodes,其部分方法会执行这个值中包含的Java字节码。经过注入恶意代码到_bytecode,致使任意代码执行漏洞。
注:Fastjson和Jackson Payload构造的方式都同样,虽然解析函数不同,可是都是将json转为object,过程是相似的。
这些序列化漏洞的根本缘由是:没有控制序列化的类型范围。
仔细看的读者会发现并无说起protobuf的反序列化漏洞,为何在protobuf里并无这些反序列化问题?
protobuf把一切都框住了,少了灵活性,天然就少漏洞。
注:IDL(Interface description language)文件:参与通信的各方须要对通信的内容须要作相关的约定(Specifications)。为了创建一个与语言和平台无关的约定,这个约定须要采用与具体开发语言、平台无关的语言来进行描述。这种语言被称为接口描述语言(IDL),采用IDL撰写的协议约定称之为IDL文件。
本文总结了java反序列化的几种方式,并回顾了java几个经典的漏洞以及对应的修复方案,但愿经过本文,你们对java反序列化漏洞有更深入的认知。
参考连接:
http://hengyunabc.github.io/thinking-about-grpc-protobuf/
https://blog.csdn.net/u011721501/article/details/78555246
https://www.freebuf.com/sectool/165655.html
https://www.cnblogs.com/he1m4n6a/p/10131566.html
https://www.jianshu.com/p/e9e631285cb0
原文出处:https://www.cnblogs.com/he1m4n6a/p/10270696.html