9-java安全——关于构造CC2链的几个问题

Posted songly_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9-java安全——关于构造CC2链的几个问题相关的知识,希望对你有一定的参考价值。

思考一下:CC2链的poc利用代码中为什么要向queue队列中添加至少2个元素?并且PriorityQueue队列中的queue属性被transient关键字修饰具有“不会序列化”语义,在反序列化过程中为什么还能从流中读取queue的数据,流中的数据又从何而来?

readObject方法是怎么从流中读取queue的数据

使用SerializationDumper工具解析对象序列化的数据,Fields字段中并没有看到PriorityQueue的queue属性,说明queue确实没有参与序列化,但是PriorityQueue重写了Serializable接口的writeObject和readObject方法实现自定义序列化与反序列化。

PriorityQueue集合中的成员属性如下:

public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable 

	private static final long serialVersionUID = -7720805057305804111L;
	private static final int DEFAULT_INITIAL_CAPACITY = 11;
	private transient Object[] queue;
	private int size = 0;
	private final Comparator<? super E> comparator;
	private transient int modCount = 0;
	

可以看到集合中的静态变量和被transient关键字修饰的成员变量不会参与序列化,最终只有size和comparator两个成员会参与序列化与反序列化过程。

通过分析PriorityQueue类的writeObject方法,发现对queue属性里的内容进行了序列化。

 有同学可能会有疑惑:java序列化机制不允许被transient关键字修饰的成员属性参与序列化,那为啥还是能调用writeObject方法进行序列化?

这句话没有错,但是有一个前提,如果使用默认的方式进行序列化(实现Serializable接口但不重写writeObject和readObject方法),transient关键字修饰的成员属性确实不会参与序列化,并且成员属性的内容也不会序列化。但是重写了writeObject和readObject方法就可以实现自定义序列化,调用writeObject方法并传入queue属性,这样的话queue中的内容依然会参与序列化。

那问题来了,queue属性里的内容到底写到了哪里呢?继续跟进分析writeObject方法做了什么事情?

可以看到writeObject方法会传入一个TemplatesImpl对象的参数

然后调用了writeObject0方法,经过一些列调用,会调用writeOrdinaryObject方法,该方法内部bout流调用了writeByte方法写入TC_OBJECT标记,其值为115,十六进制为0x73。

接着调用writeClassDesc方法,该方法内部调用了writeNonProxyDesc方法写入类描述信息,也就是写入TC_CLASSDESC标记,其值为114,十六进制为0x72

接着调用了writeNonProxy方法开始写入对象的信息:

    void writeNonProxy(ObjectOutputStream out) throws IOException 
		//写入当前对象所属类名
        out.writeUTF(name);
        //写入suid
		out.writeLong(getSerialVersionUID());

        byte flags = 0;
        if (externalizable) 
            flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
            int protocol = out.getProtocolVersion();
            if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) 
                flags |= ObjectStreamConstants.SC_BLOCK_DATA;
            
         else if (serializable) 
            flags |= ObjectStreamConstants.SC_SERIALIZABLE;
        
        if (hasWriteObjectData) 
            flags |= ObjectStreamConstants.SC_WRITE_METHOD;
        
        if (isEnum) 
            flags |= ObjectStreamConstants.SC_ENUM;
        
        out.writeByte(flags);
		//写入属性字段个数
        out.writeShort(fields.length);
		//写入字段信息
        for (int i = 0; i < fields.length; i++) 
            ObjectStreamField f = fields[i];
            out.writeByte(f.getTypeCode());
            out.writeUTF(f.getName());
            if (!f.isPrimitive()) 
                out.writeTypeString(f.getTypeString());
            
        
    

写入的类名为com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,写入的suid为0x09 57 4f c1 6e ac ab 33,接着依次写入对象的成员属性信息。

queue数组中第一个元素写入完毕,接着writeObject方法写入第二个元素,由于这两个元素都属于同一对象,第二次写入的时候并不会再次写入该对象的内容,而是会写入该对象的newHandle(对象引用),TemplatesImpl对象的newHandle值就是0x007e0012,TC_REFERENCE标记表示这是对一个对象引用的引用。

objectAnnotation字段的位置就是queue数据序列化的数据,如下所示:

 objectAnnotation
          TC_BLOCKDATA - 0x77
            Length - 4 - 0x04
            Contents - 0x00000003
		  //writeObject开始写入queue中第一个元素数据
          TC_OBJECT - 0x73
            TC_CLASSDESC - 0x72
              className
                Length - 58 - 0x00 3a
                Value - com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl - 0x636f6d2e73756e2e6f72672e6170616368652e78616c616e2e696e7465726e616c2e78736c74632e747261782e54656d706c61746573496d706c
              serialVersionUID - 0x09 57 4f c1 6e ac ab 33
              newHandle 0x00 7e 00 0e
              classDescFlags - 0x03 - SC_WRITE_METHOD | SC_SERIALIZABLE
              fieldCount - 9 - 0x00 09
              Fields
                0:
                  Int - I - 0x49
                  fieldName
                    Length - 13 - 0x00 0d
                    Value - _indentNumber - 0x5f696e64656e744e756d626572
                1:
                  Int - I - 0x49
                  fieldName
                    Length - 14 - 0x00 0e
                    Value - _transletIndex - 0x5f7472616e736c6574496e646578
                2:
                  Boolean - Z - 0x5a
                  fieldName
                    Length - 21 - 0x00 15
                    Value - _useServicesMechanism - 0x5f75736553657276696365734d656368616e69736d
                3:
                  Object - L - 0x4c
                  fieldName
                    Length - 25 - 0x00 19
                    Value - _accessExternalStylesheet - 0x5f61636365737345787465726e616c5374796c657368656574
                  className1
                    TC_REFERENCE - 0x71
                      Handle - 8257546 - 0x00 7e 00 0a
                4:
                  Object - L - 0x4c
                  fieldName
                    Length - 11 - 0x00 0b
                    Value - _auxClasses - 0x5f617578436c6173736573
                  className1
                    TC_STRING - 0x74
                      newHandle 0x00 7e 00 0f
                      Length - 59 - 0x00 3b
                      Value - Lcom/sun/org/apache/xalan/internal/xsltc/runtime/Hashtable; - 0x4c636f6d2f73756e2f6f72672f6170616368652f78616c616e2f696e7465726e616c2f78736c74632f72756e74696d652f486173687461626c653b
                5:
                  Array - [ - 0x5b
                  fieldName
                    Length - 10 - 0x00 0a
                    Value - _bytecodes - 0x5f62797465636f646573
                  className1
                    TC_STRING - 0x74
                      newHandle 0x00 7e 00 10
                      Length - 3 - 0x00 03
                      Value - [[B - 0x5b5b42
                6:
                  Array - [ - 0x5b
                  fieldName
                    Length - 6 - 0x00 06
                    Value - _class - 0x5f636c617373
                  className1
                    TC_REFERENCE - 0x71
                      Handle - 8257547 - 0x00 7e 00 0b
                7:
                  Object - L - 0x4c
                  fieldName
                    Length - 5 - 0x00 05
                    Value - _name - 0x5f6e616d65
                  className1
                    TC_REFERENCE - 0x71
                      Handle - 8257546 - 0x00 7e 00 0a
                8:
                  Object - L - 0x4c
                  fieldName
                    Length - 17 - 0x00 11
                    Value - _outputProperties - 0x5f6f757470757450726f70657274696573
                  className1
                    TC_STRING - 0x74
                      newHandle 0x00 7e 00 11
                      Length - 22 - 0x00 16
                      Value - Ljava/util/Properties; - 0x4c6a6176612f7574696c2f50726f706572746965733b
              classAnnotations
                TC_ENDBLOCKDATA - 0x78
              superClassDesc
                TC_NULL - 0x70
			//TemplatesImpl对象的引用	
            newHandle 0x00 7e 00 12
            classdata
              com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
                values
                  _indentNumber
                    (int)0 - 0x00 00 00 00
                  _transletIndex
                    (int)-1 - 0xff ff ff ff
                  _useServicesMechanism
                    (boolean)false - 0x00
                  _accessExternalStylesheet
                    (object)
                      TC_STRING - 0x74
                        newHandle 0x00 7e 00 13
                        Length - 3 - 0x00 03
                        Value - all - 0x616c6c
                  _auxClasses
                    (object)
                      TC_NULL - 0x70
                  _bytecodes
                    (array)
                      TC_ARRAY - 0x75
                        TC_CLASSDESC - 0x72
                          className
                            Length - 3 - 0x00 03
                            Value - [[B - 0x5b5b42
                          serialVersionUID - 0x4b fd 19 15 67 67 db 37
                          newHandle 0x00 7e 00 14
                          classDescFlags - 0x02 - SC_SERIALIZABLE
                          fieldCount - 0 - 0x00 00
                          classAnnotations
                            TC_ENDBLOCKDATA - 0x78
                          superClassDesc
                            TC_NULL - 0x70
                        newHandle 0x00 7e 00 15
                        Array size - 1 - 0x00 00 00 01
                        Values
                          Index 0:
                            (array)
                              TC_ARRAY - 0x75
                                TC_CLASSDESC - 0x72
                                  className
                                    Length - 2 - 0x00 02
                                    Value - [B - 0x5b42
                                  serialVersionUID - 0xac f3 17 f8 06 08 54 e0
                                  newHandle 0x00 7e 00 16
                                  classDescFlags - 0x02 - SC_SERIALIZABLE
                                  fieldCount - 0 - 0x00 00
                                  classAnnotations
                                    TC_ENDBLOCKDATA - 0x78
                                  superClassDesc
                                    TC_NULL - 0x70
                                newHandle 0x00 7e 00 17
                                Array size - 1455 - 0x00 00 05 af
                                Values
                                 //省略......
                  _class
                    (array)
                      TC_NULL - 0x70
                  _name
                    (object)
                      TC_STRING - 0x74
                        newHandle 0x00 7e 00 18
                        Length - 13 - 0x00 0d
                        Value - TemplatesImpl - 0x54656d706c61746573496d706c
                  _outputProperties
                    (object)
                      TC_NULL - 0x70
                objectAnnotation
                  TC_BLOCKDATA - 0x77
                    Length - 1 - 0x01
                    Contents - 0x00
                  TC_ENDBLOCKDATA - 0x78
		   //写入queue中第二个元素
          TC_REFERENCE - 0x71
            Handle - 8257554 - 0x00 7e 00 12
          TC_ENDBLOCKDATA - 0x78

在java序列化规范中,从objectAnnotation表示写入序列化时自定义的数据,因此queue中的元素都会写入到objectAnnotation字段开始的位置。第二次写入queue数组的元素并不会直接写入数据,而是直接写入TemplatesImpl对象的引用。

TC_REFERENCE标记表示(Handle - 8257554 - 0x00 7e 00 12)这段数据是“引用了”一个序列化对象的引用,Handle表示该序列化对象的引用(TemplatesImpl对象的newHandle引用),也就是说当其他地方需要引用该序列化对象时,就会使用TC_REFERENCE来标记Handle。

通过分析writeObject方法我们知道queue队列中的数据仍然可以参与自定义序列化与反序列化,需要注意的是必须自己定义和控制数据解析的规则,说白了就是你怎么序列化的,就必须怎么反序列化,如果不遵守规范数据就会出错。

关于queue队列中为什么要添加2个元素的问题?原因在于,queue队列在反序列化过程中readObject方法中size属性会记录队列中元素的个数,接着调用了一个heapify方法,且该方法内部的for循环会判断size的个数,如果size值小于2的话不会调用siftDown方法,也不会调用comparator比较器的compare方法进行排序,最终不会触发之前构造的利用链。

    private void heapify() 
        for (int i = (size >>> 1) - 1; i >= 0; i--)
            siftDown(i, (E) queue[i]);
    

以上是关于9-java安全——关于构造CC2链的几个问题的主要内容,如果未能解决你的问题,请参考以下文章

9-java安全——关于构造CC2链的几个问题

Java安全之Commons Collections3分析

关于js中原型链的理解

前沿技术非侵入式生物识别安全与区块链的集成方式

8-java安全——java反序列化CC2链分析

8-java安全——java反序列化CC2链分析