干货Java反序列化漏洞总结

Posted SecPulse安全脉搏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了干货Java反序列化漏洞总结相关的知识,希望对你有一定的参考价值。

1

前言

什么是序列化和反序列化

Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。反序列化就是通过序列化后的字段还原成这个对象本身。但标识不被序列化的字段是不会被还原的。

序列化有什么用

1)网站相应的session对象存储在硬盘上,那么保存在session中的内容就必须实现相关的序列化操作。

2)如果使用的java对象要在分布式中使用或者在rmi远程调用的网络中使用的话,那么相关的对象必须实现java序列化接口。


2

Java反序列化类型

我们最常见就是原生的java反序列化类型,其实java中有几种方式可以执行反序列化,本文目的也是对这几种类型的反序列化方法进行归纳和总结。

1、Java原生序列化

Java包中自带的类InputStream和OutputStream,它们之间可以互相转化,使用writeObject序列化,使用readObject反序列化。【代码行请左右滑动查看全部内容】

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);

   }

}


2、Json序列化

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;

}


3、Fastjson反序列化

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);  

    }  

}


4、Protobuf 反序列化

Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。

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);


3

各类反序列化比较

4

反序列化漏洞简介

除了使用protobuf进行反序列化没有出现过漏洞,其他方式的序列化都曾出现过漏洞。下面将简单介绍下漏洞,详细的漏洞和exp构造方法大家可以去网上搜索关键字查看(java几个反序列化漏洞exp构造过程都十分精彩,推荐大家认真阅读下)


1、Object Serialize 漏洞

Apache Commons Collections中实现了TransformedMap ,该类可以在一个元素被添加/删除/或是被修改时(即key或value:集合中的数据存储形式即是一个索引对应一个值,就像身份证与人的关系那样),会调用transform方法自动进行特定的修饰变换。


TransformedMap.decorate方法,预期是对Map类的数据结构进行转化,该方法有三个参数。

  • 第一个参数为待转化的Map对象

  • 第二个参数为Map对象内的key要经过的转化方法(可为单个方法,也可为链,也可为空)

  • 第三个参数为Map对象内的value要经过的转化方法

通过对第三个参数通过构造ChainedTransformer链,通过一系列变化,最终执行系统命令。

2、Jackson-databind 漏洞

Jackson是一套开源的java序列化与反序列化工具框架,可将java对象序列化为xml和json格式的字符串及提供对应的反序列化过程。由于其解析效率较高,目前是Spring MVC中内置使用的解析方式,该漏洞的触发条件是ObjectMapper反序列化前调用了enableDefaultTyping方法。该方法允许json字符串中指定反序列化java对象的类名,而在使用Object、Map、List等对象时,可诱发反序列化漏洞,导致可执行任意命令。

3、FastJson 漏洞

fastjson在解析json的过程中,支持使用autoType来实例化某一个具体的类,并通过json来填充其属性值。而JDK自带的类com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl中有一个私有属性_bytecodes,其部分方法会执行这个值中包含的Java字节码。通过注入恶意代码到_bytecode,导致任意代码执行漏洞。

注:Fastjson和Jackson Payload构造的方式都一样,虽然解析函数不一样,但是都是将json转为object,过程是类似的。

5

阻止反序列化漏洞

1、Java Serialization
  • jdk里增加了一个filter机制

     http://openjdk.java.net/jeps/290 

    这个一开始是出现在jdk9上的,后面移值回jdk6/7/8上,如果安装的jdk版本是比较新的,可以找到相关的类

  • Oracle打算废除java序列化:

    https://www.infoworld.com/article/3275924/java/oracle-plans-to-dump-risky-java-serialization.html

2、jackson-databind

  • jackson-databind里是过滤掉一些已知的类,参见SubTypeValidator.java

  • jackson-databind的CVE issue列表

3、fastjson

  • fastjson通过一个denyList来过滤掉一些危险类的package,参见ParserConfig.java

  • fastjson在新版本里denyList改为通过hashcode来隐藏掉package信息,但通过这个DenyTest5可以知道还是过滤掉常见危险类的package

  • fastjson在新版本里默认把autoType的功能禁止掉了


这些序列化漏洞的根本原因是:没有控制序列化的类型范围。


仔细看的读者会发现并没有提及protobuf的反序列化漏洞,为什么在protobuf里并没有这些反序列化问题?

  • protobuf在IDL里定义好了package范围

  • protobuf的代码都是自动生成的,怎么处理二进制数据都是固定的

protobuf把一切都框住了,少了灵活性,自然就少漏洞。

注:IDL(Interface description language)文件:参与通讯的各方需要对通讯的内容需要做相关的约定(Specifications)。为了建立一个与语言和平台无关的约定,这个约定需要采用与具体开发语言、平台无关的语言来进行描述。这种语言被称为接口描述语言(IDL),采用IDL撰写的协议约定称之为IDL文件。

6

总结

本文总结了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://kevien.github.io/2018/06/18/FastJson%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E(%E7%BB%AD)/

https://www.jianshu.com/p/e9e631285cb0


一审Akuma/二审viga

↙↙↙ 点击 ”阅读原文“ 与作者展开话题探讨,直面交流

以上是关于干货Java反序列化漏洞总结的主要内容,如果未能解决你的问题,请参考以下文章

JAVA代码审计之Shiro反序列化漏洞分析

Java反序列化漏洞总结

反序列化漏洞复现总结

JAVA反序列化漏洞解决办法

CommonCollections1反序列化利用链分析

麻了!Fastjson 再曝反序列化漏洞。。