[Java反序列化]JDK7U21原生反序列化利用链分析

Posted Y4tacker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Java反序列化]JDK7U21原生反序列化利用链分析相关的知识,希望对你有一定的参考价值。

写在前面

这段时间看了也跟踪了CC链,CB链,也跟踪调试了shiro的两个链子,XMLDecoder等,就用JDKK7U21原生反序列化利用链来暂时结束下最近的学习

利用链

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()

JDK7U21原生反序列化利用链分析

JDK7u21的核心点就是sun.reflect.annotation.AnnotationInvocationHandler,我们来看看AnnotationInvocationHandler这个方法

再看

可以很清楚的分析到equalsImpl这个方法
首先是利用反射获取this.type中的所有方法,之后进行遍历其中的方法并执行,如果我们把this.type赋为一个类,岂不是能调用里面的所有方法了,还记得那个TemplatesImpl对象么,我们就可以利用它来进行字节码的加载执行了
接下来我们发现在AnnotationInvocationHandler下面的invoke方法

这里我们其实发现,它实现了InvocationHandler

因此我们不难想到一个东西,动态代理,当调用equal方法时,就能实现完整的利用链,这里前辈们想到的是利用HashSet,因为HashSet中储存的对象不允许重复,所以在添加对象的时候,势必会涉及到比较操作。
可以看到在HashSetreadObject方法

这里调用了equal方法,但是从函数当中也能看出前提是他们的hash值相等

接下来我们就要让proxy对象的哈希值,等于TemplateImpl对象的哈希值,我们来看看hash的计算方法
我们来看看这里面的hash方法

这里我们发现主要是对象的hashCode方法

那我们就来看看这两个方法,首先是TemplatesImplhashcode方法,无法Debug调试跟踪,最后网上说是一个Native方法,难怪,但是我们不难发现每一次运行都在变,如何处理看后面分析

而看看我们代理的HashCode呢,会通过AnnotationInvocationHandlerinvoke ,进而调用到AnnotationInvocationHandlerhashCodeImpl
我们看看hashCodeImpl,它遍历memberValues中的每个keyvalue,计算 (127 * key.hashCode()) ^ value.hashCode()并求和

private int hashCodeImpl() {
        int var1 = 0;

        Entry var3;
        for(Iterator var2 = this.memberValues.entrySet().iterator(); var2.hasNext(); var1 += 127 * ((String)var3.getKey()).hashCode() ^ memberValueHashCode(var3.getValue())) {
            var3 = (Entry)var2.next();
        }

        return var1;
    }

再来看这个当只有一个keyvalue时,简化成 了(127 * key.hashCode()) ^ value.hashCode()
因此不难想到当key.hashCode()等于0时,任何数异或0的结果仍是他本身,所以该哈希简化成value.hashCode()value 就是TemplateImpl对象时,这两个哈希就变成完全相等,因此我们只需要拿到一个hashCode是0的对象,网上给跑出来的是字符串f5a5a608

我们整理下利用思路

  1. 构造TemplatesImpl并将执行的字节码赋值
  2. 实例化一个HashMap,并添加keyf5a5a608,恶意构造好的TemplatesImpl加入到map中
  3. 利用反射实例化AnnotationInvocationHandler
  4. AnnotationInvocationHandler对象设置动态代理
  5. 实例化HashSet,并将TemplatesImpl设置的代理这两个对象放进去

流程跟踪

首先通过readObject调用,之后

跟进去看看,首先第一个对象Hash计算完添加

由于第二个对象hash与第一个相同,调用equal方法

通过动态代理触发equalsImpl的调用

接下来就是遍历Template里面的方法并通过反射执行,可以看到这里有执行newTransformer


调用getTransletInstance方法

继续跟踪调用defineTransletClasses方法

跟入defineClass

加载字节码

别忘了这里有一个验证加载的字节码的对象必须是class com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet的子类哦


实例化

成功弹出计算器

参考文章

动态代理
JavaThings/JDK7u21
【技术分享】JDK7u21反序列化
jdk7u21反序列化调试

以上是关于[Java反序列化]JDK7U21原生反序列化利用链分析的主要内容,如果未能解决你的问题,请参考以下文章

[Java反序列化]JDK7u21反序列化链学习

[Java反序列化]JDK7u21反序列化链学习

JRE8u20反序列化漏洞分析

12-java安全——java反序列化CC7链分析

12-java安全——java反序列化CC7链分析

12-java安全——java反序列化CC7链分析