1. 程式人生 > >Java反序列化漏洞總結

Java反序列化漏洞總結

新的 私有 orm decorate 靈活 調用 序列 很好 方式

前言

什麽是序列化和反序列化

Java 提供了一種對象序列化的機制,該機制中,一個對象可以被表示為一個字節序列,該字節序列包括該對象的數據、有關對象的類型的信息和存儲在對象中數據的類型。反序列化就是通過序列化後的字段還原成這個對象本身。但標識不被序列化的字段是不會被還原的。

序列化有什麽用

1)網站相應的session對象存儲在硬盤上,那麽保存在session中的內容就必須實現相關的序列化操作。

2)如果使用的java對象要在分布式中使用或者在rmi遠程調用的網絡中使用的話,那麽相關的對象必須實現java序列化接口。

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

各方式反序列化比較

技術分享圖片

各序列化漏洞簡介

除了使用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,過程是類似的。

防止反序列化漏洞

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文件。

總結:

本文總結了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

Java反序列化漏洞總結