Java 反序列化 - commons collection 之困(一)

#01多余的碎碎念

说到 java 反序列化,去搜索的话能看到网上有很多分析关于 commons collection 利用链的文章,emm 我一开始看不懂,看到很多代码的图头晕。

这篇文章的话其实是我跟着 p 神的文章一路走下来的,所以整个逻辑会按照 p 神的文章走。那对于反射、动态代理也有一些自己的理解,所以就记录下来。希望也给你们多一个角度的理解。

#02反射

为什么要先讲反射?因为你去看他的利用链的实现,会发现都会运用到反射。

java 中有两个类用来执行命令,一个是 Runtime ,一个是 ProcessBuilder 。那这两个类都是没有实现 Serializable (序列化)接口的,也就是不能进行反序列化,我们想想,如果我们执行命令的类不能进行反序列化,也就是不能利用反序列化漏洞还原该类,那我们是不是也就不能执行命令了?这时候我们其实就可以通过反射来创建该类的对象【也就是常说的运行时对象】,调用该类的方法。

所以我们首先来介绍一下反射,只要我们知道需要用的类名、方法名及参数类型,我们就能通过反射机制创建任意类对象、调用任意类方法。

举一较常用的例子:

package com.govuln;import java.lang.reflect.InvocationTargetException;public class test {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {Class clazz = Runtime.class;clazz.getMethod("exec", String.class).invoke(clazz.getMethod("getRuntime").invoke(null), "calc.exe");}}

这里其实就是通过反射实现了调用计算器的效果,如果不用反射,我们正常代码逻辑就是 Runtime.getRuntime().exec(“calc”); 就好了。

那么接下来为了理解上面的代码一步步看反射的语法。

我们从下往上推,最开始看他方法调用的部分:

正常方法调用语法:obj.方法(args)

反射方法调用语法:方法.invoke(Object obj, Object… args) ,invoke 中传入的参数为调用此方法的对象,及方法需传入的参数值。

而此时的方法也应是通过反射得到的。语法:class.getMethod(String name, Class… parameterTypes) ,getMethod 方法中传入的为我们需调用的方法名以及方法的参数类型。

而这里的 class 就是字节码文件对象,也是类在内存中的体现。字节码文件也就是 java 源文件编译后生成的 .class 文件,JVM 将 .class 文件加载到内存执行,将编译后的 .class 文件当作字节码文件对象。那么获取当前 class 的语法:

1、类.class
2、Class.forName(类的全路径)

所以我们刚才代码中获取 Runtime 的字节码文件对象其实是通过第一种方式获取到的。

讲到这里前面代码中通过反射执行 Runtime 的 exec 方法应该可以理解得差不多:首先获取到 Runtime 的字节码文件,接下来获取到其方法 exec ,然后进行方法调用。那这里还有一个地方就是方法调用的时候可能不明白:invoke 传入的参数,调用此方法的对象。clazz.getMethod("getRuntime").invoke(null) 为什么是这样生成对象的呢?那其实反射获取到目标对象有两种方式,第一种就是通过上面代码中的形式,这种是通过 Runtime 去调用静态方法 getRuntime ,从而得到一个 Runtime 对象。

这里通过这种方式是因为 Runtime 类的构造方法是私有的(意味着非 Runtime 类无法访问到生成对象时需调用的构造方法,作用域的限制)。所以他有一个统一的路径去获取到 Runtime 对象,那就是通过调用静态方法 getRuntime 。那么调用静态方法时,传入的参数调用此方法的对象可以为 null,当然传入上面代码中 clazz 对象也是可以的。

到这里上面通过反射执行计算器的命令应该就都能理解了。我们还讲一下第二种方式来获取目标对象哦,那就是通过基本的构造方法来获取到目标对象,在反射中,我们可以通过
clazz.getDeclaredConstructor() 方法获取到类的私有构造方法,并设置 Accessible 为 true ,即可通过获取的构造器来 newInstance 获取到目标对象,newInstance 方法中传入的参数是创建目标对象时需要的初始化对象,没有则不传。所以也就是可以这样执行命令:

Class clazz = Class.forName("java.lang.Runtime");
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
Runtime runtime = (Runtime) constructor.newInstance();
clazz.getMethod("exec", String.class).invoke(runtime, "calc");

那么通过另一个类来执行命令的话,大家可以自己先写一下:

反射:

Class clazz = ProcessBuilder.class;
clazz.getMethod("start").invoke(clazz.getConstructor(List.class).newInstance(Arrays.asList("calc")));

正常:

ProcessBuilder processBuilder = new ProcessBuilder("calc");
processBuilder.start();

【——全网最全的网络安全学习资料包分享给爱学习的你,关注我,私信回复“资料领取”获取——】
1.网络安全多个方向学习路线2.全网最全的CTF入门学习资料3.一线大佬实战经验分享笔记4.网安大厂面试题合集5.红蓝对抗实战技术秘籍6.网络安全基础入门、Linux、web安全、渗透测试方面视频

#03动态代理

为什么要讲动态代理?emmm 因为利用链会用到。

动态代理,其实挺像相亲的【也到了要相亲的年纪,也挺和时宜 233 】。当男孩心悦于某女孩,那么肯定都会先要经过父母这关的,当父母觉得这个男孩子 ok ,那么好,你们俩去进行下一步操作。那这里父母其实就相当于我们的动态代理类,其实也相当于一个拦截过滤器的作用,使其不直接与类对象进行交互而是通过代理对象去进行交互,想要调用该类对象的某方法时:

  1. 首先获取到通过代理类生成的代理对象:Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 返回某个对象的代理对象。
  • 第一个参数是 ClassLoader ,指明生成代理对象使用哪个类装载器;
  • 第二个参数是指明生成哪个对象的代理对象,通过接口指定;
  • 第三个参数是一个实现了 InvocationHandler 接口的对象,该对象有个 invoke 方法里面实现了代理对象要去做什么事的逻辑。
  1. 接下来通过代理对象调用目标对象的方法,实际上先调用了 h 的 invoke 方法,接着再去调用具体对象的方法。

可以看一个例子理解:

public class App {public static void main(String[] args) {InvocationHandler handler = new ExampleInvocationHandler(new HashMap());Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);proxyMap.put("hello", "world");String result = (String)proxyMap.get("hello");System.out.println(result);}
}
public class ExampleInvocationHandler implements InvocationHandler {protected Map map;public ExampleInvocationHandler(Map map){this.map = map;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (method.getName().compareTo("get") == 0){System.out.println("Hook method:" + method.getName());return "hacked object";}return method.invoke(this.map, args);}
}

运行结果:

#04不重要的结尾

好啦,讲到这里文章已经很长了,下一篇再一起分析 commons collection 的利用链吧。

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

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

相关文章

python LLM工具包

阿里云镜像pypi http://mirrors.aliyun.com/pypi/simple/ modelscope魔塔 pip install modelscope https://modelscope.cn/docs/models/download Sentence-transformers pip install -U sentence-transformers pip3 install torch -i https://pypi.tuna.tsinghua.edu.cn/sim…

Linux账号和权限管理

用户账户管理 理论 /etc/passwd 该目录用于保存用户名,宿主目录,登录shel等基本信息 /etc/shadow 该目录用于保存 用户密码,账户有效期等信息 图上每一行中都有用“:”隔断的字段 字段含义: 第1字段:用户账号的名…

晋升系列4:学习方法

每一个成功的人,都是从底层开始打怪,不断的总结经验,一步一步打上来的。在这个过程中需要坚持、总结方法论。 对一件事情长久坚持的人其实比较少,在坚持的人中,不断的总结优化的更少,所以最终达到高级别的…

win32汇编环境,对话框中使用树形视图示例四

;运行效果,当点击张辽时,展示张辽的图像 ;当点击曹仁时,展示曹仁的图像 ;win32汇编环境,对话框中使用树形视图示例四 ;当点击树形视图treeview控件中的某项时,展示某些功能。这里展示的是当点到某个将领时,显示某个将领的图像 ;直接抄进RadAsm可编译运行。重要部分加备注。…

智慧停车小程序:实时车位查询、导航与费用结算一体化

智慧停车小程序:实时车位查询、导航与费用结算一体化 一、城市停车困境的数字化突围 中国机动车保有量突破4.3亿辆,但车位供给缺口达8000万。传统停车管理模式存在三大致命伤: 盲盒式寻位:62%的车主遭遇"地图显示有位,到场已满员"的窘境迷宫式导航:商场停车场…

Windows server网络安全

摘要 安全策略 IP安全策略,简单的来说就是可以通过做相应的策略来达到放行、阻止相关的端口;放行、阻止相关的IP,如何做安全策略,小编为大家详细的写了相关的步骤: 解说步骤: 阻止所有: 打…

充电桩快速搭建springcloud(微服务)+前后端分离(vue),客户端实现微信小程序+ios+app使用uniapp(一处编写,处处编译)

充电桩管理系统是专为中小型充电桩运营商、企业和个人开发者设计的一套高效、灵活的管理平台。系统基于Spring Cloud微服务架构开发,采用模块化设计,支持单机部署与集群部署,能够根据业务需求动态扩展。系统前端使用uniapp框架,可…

小肥柴慢慢手写数据结构(C篇)(4-3 关于栈和队列的讨论)

小肥柴慢慢学习数据结构笔记(C篇)(4-3 关于栈和队列的讨论) 目录1 双端栈/队列2 栈与队列的相互转化2-1 栈转化成队列2-2 队列转化成栈 3 经典工程案例3-1 生产者和消费者模型(再次重温环形缓冲区)3-2 MapR…

labview实现大小端交换移位

在解码时遇到了大小端交换的问题,需要把高低字节的16进制值进行互换,这里一时间不知道怎么操作,本来打算先把16进制转字节数组,算出字节数组的大小,然后通过模2得到0,1,来判断是否为奇数位和偶数…

在Windows系统上安装和配置Redis服务

🌟 在Windows系统上安装和配置Redis服务 Redis是一个高性能的键值存储数据库,广泛用于缓存、消息队列和实时分析等场景。虽然Redis最初是为Linux设计的,但也有Windows版本可供使用。今天,我将详细介绍如何在Windows系统上安装Red…

Ateme在云端构建可扩展视频流播平台

Akamai Connected Cloud帮助Ateme客户向全球观众分发最高质量视频内容。 “付费电视运营商和内容提供商现在可以在Akamai Connected Cloud上通过高质量视频吸引观众,并轻松扩展。”── Ateme首席战略官Rmi Beaudouin ​ Ateme是全球领先的视频压缩和传输解决方案提…

DeepSeek进阶应用(一):结合Mermaid绘图(流程图、时序图、类图、状态图、甘特图、饼图)

🌟前言: 在软件开发、项目管理和系统设计等领域,图表是表达复杂信息的有效工具。随着AI助手如DeepSeek的普及,我们现在可以更轻松地创建各种专业图表。 名人说:博观而约取,厚积而薄发。——苏轼《稼说送张琥》 创作者&…

deepseek R1提供的3d迷宫设计方案

一、技术选型方案 核心渲染技术 🎨 采用Raycasting算法模拟3D透视效果使用Canvas 2D上下文进行逐像素绘制材质贴图系统实现墙面差异化表现 迷宫数据结构 🗺️ 二维数组存储迷宫布局(0:通路,1:墙体)递归回溯算法生成随…

时序数据库TimescaleDB基本操作示例

好的&#xff01;以下是使用 TimescaleDB 的 Java 示例&#xff08;基于 JDBC&#xff0c;因为 TimescaleDB 是 PostgreSQL 的扩展&#xff0c;官方未提供独立的 Java SDK&#xff09;&#xff1a; 1. 添加依赖&#xff08;Maven&#xff09; <dependency><groupId&g…

linux下的网络抓包(tcpdump)介绍

linux下的网络抓包[tcpdump]介绍 前言tcpdump1. 安装 tcpdump2. 基本抓包命令3. 过滤器使用4. 保存捕获的数据包 异常指标1. 连接建立与断开相关指标异常 SYN 包异常 FIN 或 RST 包 2. 流量相关指标异常流量峰值异常源或目的 IP 流量 3. 端口相关指标异常端口使用端口扫描 4. 数…

C/C++中使用CopyFile、CopyFileEx原理、用法、区别及分别在哪些场景使用

文章目录 1. CopyFile原理函数原型返回值用法示例适用场景 2. CopyFileEx原理函数原型返回值用法示例适用场景 3. 核心区别4. 选择建议5. 常见问题6.区别 在Windows系统编程中&#xff0c;CopyFile和CopyFileEx是用于文件复制的两个API函数。它们的核心区别在于功能扩展性和控制…

Bash和Zsh在处理大文件时差异

在处理大文件时&#xff0c;Bash 和 Zsh 的差异主要体现在几个方面&#xff1a; 1. 脚本执行速度 Bash: 性能: Bash在执行脚本时通常表现良好&#xff0c;尤其是在处理大量数据或大文件时。Bash的脚本执行速度相对较快&#xff0c;适合大多数日常使用场景。优化: Bash在处理大…

不同AI生成的PHP版雪花算法

OpenAI <?php /*** Snowflake 雪花算法生成器* 生成的 64 位 ID 结构&#xff1a;* 1 位 保留位&#xff08;始终为0&#xff0c;防止负数&#xff09;* 41 位 时间戳&#xff08;毫秒级&#xff0c;当前时间减去自定义纪元&#xff09;* 5 位 数据中心ID* 5 …

Android Telephony 四大服务和数据网络控制面数据面介绍

在移动通信和Android系统中,涉及的关键概念和服务以及场景案例说明如下: 一、概念 (一)Android Telephony 的四大服务 介绍Telephony Data 与 Android Data 的四大服务在Android系统中,与电话(Telephony)和移动数据(Data)相关的核心服务主要包括以下四类: 1. Tele…

浙江大学:DeepSeek行业应用案例集(153页)(文末可下载PDF)

浙江大学&#xff1a;DeepSeek行业应用案例集&#xff08;153页&#xff09;&#xff08;文末可下载PDF&#xff09; 全文链接&#xff1a;浙江大学&#xff1a;DeepSeek行业应用案例集&#xff08;153页&#xff09;&#xff08;文末可下载PDF&#xff09; | AI探金 全文链接&…