Java漏洞原理与实战

一、基本概念

1、序列化与反序列化

(1)序列化:将对象写入IO流中,ObjectOutputStream类的writeobject()方法可以实现序列化

(2)反序列化:从IO流中恢复对象,ObjectinputStream类的readObject()方法用于反序列化

(3)意义:序列化机制允许将实现序列化的Java对象转换为字节序列,这些字节序列可以保存到磁盘上,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在

(4)序列化与反序列化是让Java对象脱离Java运行环境的一种手段,可以有效的实现多平台之间的通信、对象持久化储存。主要应用在以下场景:

HTTP:多平台之间的通信,管理等,也可以用于流量带外

RMI:是Java的一组拥护开发分布式应用程序的API,实现了不同操作系统之间程序的方法调用。值得注意的是,RMI的传输100%基于反序列化,Java RMI的默认端口是1099端口

JMX:JMX是一套标准的代理和服务,用户可以在任何Java应用程序中使用这些代理和服务实现管理,中间件weblogic的管理页面就是基于JMX开发的,而JBoss则整个系统都基于JMX框架

(5)Java代码审计思路

如果是Java原生类,则需要入口类readObject方法,同时实现了序列化接口,使其可以进行有效的反序列化,此时如果存在DNS解析,或者实现反序列化(利用Runtime对象进行类反射操作)

需要有最终的执行函数(可以执行代码或者命令),比如Runtime.getRuntime().exec,ProcessBuilder().start,getHostAddress,文件读写...等等,这些函数需要自己平常去收集,这样审计起来会更得心应手

2、Java类反射机制

(1) 反射机制的作用:通过Java语言中的反射机制可以操作字节码文件(可以读和修改字节码文件),可以通过另外的方式调用到类的属性和方法,甚至私有属性和方法

(2)反射机制的相关类在java.lang.reflect.*包下面

(3)反射机制的相关类有哪些:Constructor、Field、Method、Class等类

(4)java.lang.Class代表字节码文件,代表整个类

(5)java.lang.reflect.Method代表字节码中的方法字节码,代表类中的方法java.lang.reflect.Constructor代表字节码中的构造方法字节码,代表类中的构造方法java.lang.reflect.Field代表字节码中的属性字节码,代表类中的属性

(6)Java中为什么要使用反射机制,直接创建对象不是更方便?

如果有多个类,每个用户所需求的对象不同,直接创建对象,就要不断的去new一个对象,非常不灵活。而Java反射机制,在运行时确定类型,绑定对象,动态编译最大限度发挥了java的灵活性

(7)获取成员变量

(8)获取并调用方法

(9)获取构造方法

(10)访问私有属性

二、类反射机制实践

package com.woniu.vul;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;class Test{public String name = "蜗牛学苑";public int age = 8;private String addr = "西安";private int price = 10000;public Test() {}public Test(int price){this.price = price;}public int setPrice(int price){System.out.println("新价格为:" + price);return price;}public int getPrice(){return this.price;}private void getAddr(){System.out.println("私有方法:" + addr);}}public class Reflect {public static void main(String[] args) throws Exception {/*Test t = new Test();System.out.println(t.getPrice());Test t1 = new Test(15000);System.out.println(t1.getPrice());System.out.println(t.name);*///使用反射机制实现属性和方法的调用(包括构造方法)//使用Class.forName可以获取到类本身,在JVM中动态加载Test类//Class clazz = Class.forName("com.woniu.vul.Test");//Class clazz = Test.class;//使用new Instance进行实例化//Test t = (Test) clazz.newInstance();//System.out.println(t.getPrice());//Object o = clazz.newInstance();  //实例化动态加载的类,类型必须是Object//        Method m1 = clazz.getMethod("getPrice");
//        int price1 = (int)m1.invoke(o,null);
//        System.out.println(price1);
//
//        Method m2 = clazz.getMethod("setPrice",int.class);
//        int price2 = (int)m2.invoke(o,15000);
//        System.out.println(price2);//调用price私有属性和getAddr私有方法,getFiled只能调用公有属性,getDeclareField才能调私有属性//Field f1 = clazz.getDeclaredField("price");//f1.setAccessible(true);  //设置私有属性可访问//System.out.println(f1.get(o));//getMethod只能调用公有方法,而getDeclareMethod才能嗲用私有方法//Method m1 = clazz.getDeclaredMethod("getAddr");//m1.setAccessible(true);//m1.invoke(o,null);//构造方法如果有参数,怎么办?Class clazz = Class.forName("com.woniu.vul.Test");Constructor c = clazz.getConstructor(int.class);  //获取到一个带参数的构造器Object o = c.newInstance(10); //用构造器去构造一个动态加载的类Method m1 = clazz.getDeclaredMethod("getPrice");int price = (int) m1.invoke(o,null);System.out.println(price);//遍历所有方法或操作Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {System.out.println(method + "   " + method.getName() + "    " + method.getModifiers());}Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {System.out.println(field + "   " + field.getName() + "    " + field.getModifiers());}}
}

三、序列化与反序列化

序列化的实现代码

package com.woniu.vul;import java.io.*;class Student implements Serializable {public String name = "";public int id = 0;public String phone = "";public Student(){System.out.println("构造方法运行");}public void study(){System.out.println("学生正在学习");}public void sleep(){System.out.println("学生正在休息");}
}public class Unserial {public void serial() throws Exception {Student s = new Student();s.name = "张三";s.id = 12345;s.phone = "188123456786";FileOutputStream fos = new FileOutputStream("./data/student.ser");ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(s);}public void unserial() throws Exception {FileInputStream fis = new FileInputStream("./data/student.ser");ObjectInputStream ois = new ObjectInputStream(fis);Student obj =(Student) ois.readObject();System.out.println(obj.name);obj.study();}public static void main(String[] args) throws Exception {Unserial us = new Unserial();//us.serial();us.unserial();}
}

序列化的内容如下:

 然后进行反序列化,切记不要去改我们的序列化内容,不然无法反序列化回去

 我们再补充两个小问题

正常情况下,高亮部分是可以被序列化的,但是如果在这之前加上transient来修饰的话就无法序列化

高亮部分的意思就是定义一个序列化版本的编号,也就是唯一标识

 

这个标识是用来干嘛的

接下来我们看看

我们重新反序列化看看效果

报错信息告诉我们是一个不可用的类

为什么不可用,让我们继续看报错信息

序列化的时候类的ID是前面的那一个,但是反序列的时候类的ID是后面那一个,序列化和反序列化的时候标识号是不一样的,意思就是这个类并不是我们需要反序列化的类

我们将代码中的ID改为其序列化时候原本的ID,那我们就可以完成反序列化的操作了

也就是说这个类在序列化的时候会记录下其类的标识UID

接下来我们看看反序列化产生的机制

首先这个序列化对象一旦有重写的方法,那我们在反序列化的时候会优先调用重写的readObject


 因为我们重写了readObject,所以就会先调用readObject,这就是Java反序列化的起点,也是唯一的起点

也就是说Java反序列化漏洞能够被利用,我们得有一个最基本的前提,就是目标类必须重写readObject方法,只有这样,代码才会被自动调用,否则就没有起点

如果不重写readObject方法的话,就不会发生Java反序列化漏洞

而我们的代码已经重写了readObject方法,所以我们可以对其利用

我们可以直接在重写方法的下面加上终点,也就是攻击者想要达到的效果,有始有终,整个攻击链才算完整

当然我们也可以使用类反射机制的手段去执行命令

因为getRuntime的实例不是纯粹的new出来的,而是通过调用getRuntime这个方法来获取其实例的,然后再通过这个实例去调用exec

加载java.lang.Runtime类

获取Runtime类中的getRuntime方法

调用Runtime方法,获取Runtime类的实例

获取Runtime类中的exec(string)方法

调用exec(String)方法,运行外部命令ifconfig

 运行代码,发现没有报错,说明应该是利用成功了,我不知道为啥不会显示执行ifconfig命令的内容,如果是Windows的话,可以将ifconfig改为calc.exe,大概率会显示出计算器

当然为了执行命令,不仅仅只有Runtime,还有ProcessBuilder

接下来我们看看其反射的调用

根据正常的调用来构造反射

先使用Class.forName这个方法来加载java.lang.ProcessBuilder这个类

然后使用Class对象的getConstructor来获取Processbuilder类的构造函数

接着使用Constructor对象的newInstance方法来创建ProcessBuilder的实例

然后使用Class对象的getMethod方法去获取ProcessBuilder中的start方法

最后使用Method对象的invoke方法去调用start方法

 然后运行,发现报错,是类型出现了错误

 我们先去看看ProcessBuilder的构造方法,它不是严格意义上的String,是String...(可变长的字符串)如果是whoami /user这条命令的话,我们得写到两个字符串里面,在Java中,对于可变长的字符串是将其放入到数组当中去

 然后我们将其修改为String[].class

然后继续运行,然后还是报错说类型不匹配

就是因为我们上面定义的是数组,下面是字符串,所以会报错

所以我们要将下面的类型转换为数组类型就可以了,也就是将其放到数组中就可以了,如下

继续运行,发现还是报错,报错信息还是类型不匹配

 我们去看看newInstace的构造方法,发现还是一个数组,它的类型是数组,数组里面的参数还是一个数组

所以这个cmd的类型要定义成二维数组,二维数组只需加两个{}即可,如下

然后去运行,发现没有报错,但是也没有回显命令的内容,应该是电脑的问题,如果是Windows的话在命令那一块改为calc.exe就可以打开计算器了

 

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

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

相关文章

每日算法【双指针算法】(Day 1-移动零)

双指针算法 1.算法题目(移动零)2.讲解算法原理3.编写代码 1.算法题目(移动零) 2.讲解算法原理 数组划分,数组分块(快排里面最核心的一步)只需把0改为tmp 双指针算法:利用数组下标来…

SQL Server 的鎖機制

SQL Server 的鎖機制是為了確保數據的一致性和事務的隔離性而設計的。以下是針對讀寫操作的鎖定行為的詳細說明: 1. 鎖的基本類型 SQL Server 的鎖主要分為以下幾類: 共享鎖(Shared Lock, S Lock) 用於讀操作(如 S…

AIP目录

专注于开发灵活API的设计文档。 AIP是总结了谷歌API设计决策的设计文档,它也为其他人提供了用文档记录API设计规则和实践的框架和系统。 基础1AIP目的和指南2AIP编号规则3AIP版本管理200先例8AIP风格与指导9术语表流程100API设计评审常见问题205Beta版本发布前置条…

CSS进度条带斑马纹动画(有效果图)

效果图 .wxml <view class"tb"><view class"tb-line" style"transform:translateX({{w%}})" /> </view> <button bind:tap"updateLine">增加进度</button>.js Page({data: {w:0,},updateLine(){this.…

【工具-Krillin AI】视频翻译、配音、语音克隆于一体的一站式视频多语言转换工具~

Krillin AI 是全能型音视频本地化与增强解决工具。这款简约而强大的工具&#xff0c;集音视频翻译、配音、语音克隆于一身&#xff0c;支持横竖屏格式输出&#xff0c;确保在所有主流平台&#xff08;哔哩哔哩&#xff0c;小红书&#xff0c;抖音&#xff0c;视频号&#xff0c…

zset.

zset 有序集合 zset 保留了 set 不能有重复元素的特点 zset 中的每个元素都有一个唯一的浮点类型的分数&#xff08;score&#xff09;与之关联&#xff0c;使得 zset 内部的元素是可以维护有序性的。但是这个有序不是用下标作为排序依据的&#xff0c;而是根据分数&#xf…

Spring 数据库编程

Spring JDBC 传统的JDBC在操作数据库时&#xff0c;需要先打开数据库连接&#xff0c;执行SQL语句&#xff0c;然后封装结果&#xff0c;最后关闭数据库连接等资源。频繁的数据库操作会产生大量的重复代码&#xff0c;造成代码冗余&#xff0c;Spring的JDBC模块负责数据库资源…

492Q 型气缸盖双端面铣削组合铣床总体设计

一、引言 492Q 型气缸盖是发动机的重要组成部分&#xff0c;其双端面的加工精度对发动机的性能和可靠性有着重要影响。设计一款适用于 492Q 型气缸盖双端面铣削的组合铣床&#xff0c;能够提高加工效率和质量&#xff0c;满足发动机生产的需求。 二、总体设计要求 加工精度&…

颚式破碎机的设计

一、引言 颚式破碎机作为矿山、建材等行业的重要破碎设备&#xff0c;其性能优劣直接影响物料破碎效率与质量。随着工业生产规模的扩大和对破碎效率要求的提高&#xff0c;设计一款高效、稳定、节能的颚式破碎机具有重要意义。 二、设计需求分析 处理能力&#xff1a;根据目…

第三阶段面试题

Nginx nginx常用模块以及其功能 proxy模块&#xff0c;进行代理功能 ssl模块&#xff0c;进行HTTPS协议的使用 gzip模块&#xff0c;进行传输数据的压缩 upstream模块&#xff0c;进行反向代理时使用 static模块&#xff0c;静态资源进行访问的模块 cache模块&#xff0…

鸿蒙NEXT开发键盘工具类(ArkTs)

export declare type KeyboardCallBack (show: boolean, height: number) > void; import { AppUtil } from ./AppUtil; import { LogUtil } from ./LogUtil; import { ArrayUtil } from ./ArrayUtil;/*** 键盘工具类* author 鸿蒙布道师* since 2025/04/18*/ export class…

基于 LabVIEW 的电液伺服阀测试台开发

开发了一种基于 LabVIEW 图形编程语言的自动测试系统&#xff0c;能够完成电液伺服阀的空载流量特性、压力增益特性、内泄漏特性等静态特性的自动测试。针对测试过程中干扰信号频段与正常信号频段接近&#xff0c;普通数字滤波器滤波效果不佳的问题&#xff0c;采用迭代滤波分解…

【uniapp】vue2 使用 Vuex 状态管理

创建store文件夹&#xff1a;store/index.js // index.js import Vue from vue import Vuex from vuex import address from ./modules/address.jsVue.use(Vuex)const store new Vuex.Store({modules: {address} })export default store 创建modules文件夹&#xff1a;modul…

c# 简单实现将Message的内容保存到txt中,超过100个则清理旧文件

using System; using System.IO; using System.Threading;public static class LogManager {private static readonly object _fileLock new object(); // 线程安全锁private const int MaxFiles 100; // 最大文件数限制private const string LogDire…

阿里云镜像加速仅支持阿里云产品了

最近在拉取docker镜像时一直报超时的错误&#xff1a; docker pull hello-world Using default tag: latest Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exce…

从零实现Git安装、使用

一、git安装 Git官方下载 1.下载exe程序 2.双击安装&#xff0c;一直点击next&#xff0c;默认安装 安装完成后&#xff0c;在任意文件夹右键&#xff0c;出现下图所示&#xff0c;即为安装成功。 3.【Git Bash Here】调出命令窗口&#xff0c;设置用户名和 email 地址。 gi…

生产环境中如何使用Caffeine+Redis实现二级缓存(详细分析了遇到的各种情况)

生产环境中如何使用CaffeineRedis实现二级缓存&#xff08;详细分析了各种情况&#xff09; 本篇主要讲解的是实现CaffeineRedis实现一个现成的使用流程。下一篇讲解什么是Caffeine以及caffeine的使用 00背景&#xff1a; 使用Caffeine和Redis的二级缓存方案源自于分布式系统…

RT-Thread开发文档合集

瑞萨VisionBoard开发实践指南 RT-Thread 文档中心 RT-Thread-【RA8D1-Vision Board】 RA8D1 Vision Board上的USB实践RT-Thread问答社区 - RT-Thread 【开发板】环境篇&#xff1a;05烧录工具介绍_哔哩哔哩_bilibili 【RA8D1-Vision Board】基于OpenMV 实现图像分类_哔哩哔哩_…

甘果桌面tv版下载-甘果桌面安卓电视版使用教程

甘果桌面 TV 版是一款备受关注的应用&#xff0c;它可以让安卓电视的界面更加个性化、操作更加便捷。接下来&#xff0c;我们就详细了解一下甘果桌面 TV 版的下载方法以及安卓电视版的使用教程。 甘果桌面 TV 版下载 打开你的安卓电视&#xff0c;找到并进入电视自带的应用商店…

RAII资源管理理解

基础介绍 RAII (Resource Acquisition Is Initialization) 是一种 C 编程范式&#xff0c;这不是一个语法特性&#xff0c;而是一种处理方式。RAII的思想&#xff1a; 资源获取与对象初始化同时发生资源释放与对象销毁同时发生通过对象的生命周期来管理资源&#xff0c;确保资…