CC1,3,6回顧

2022-11-13 06:01:09

前言

前面陸續學習了CC1,CC3,CC6,以及TemplatesImpl以及改造,有點亂,正所謂溫故而知新嘛,所以這篇就回顧一下,捋一捋,解決一些細節問題。

CC1

由於CC1要介紹CC鏈的幾個關鍵類,所以寫了三篇

  1. InvokerTransformer,其transform可以執行任意方法,
  2. ConstantTransformer作用是拿到一個危險類,如RunTime等等,
  3. ChainedTransformer作用是將幾個Transformer串聯起來

這三種搭配就可以執行任意方法

  1. TransformedMap:用來修飾Map,被修飾過的Map在新增新的元素時,將可以執⾏⼀個回撥,也就是說可以呼叫其他的tramsform

  2. AnnotationInvocationHandler:第四點說了,觸發漏洞的核心是向Map加入新的元素,在實際反序列化利用的時候,我們需要找到一個類,它在反序列化的readObject邏輯裡有類似的寫入操作。這個類剛好符合條件。

到這兒,算是一條完整的CC利用鏈了。

  1. LazyMap:作用和TransformedMap類似,都是為了執行transform,區別就是TransformedMap是在寫入元素的時候執行會transform,而LazyMap是在其get方法中執行的factory.transform
  2. 動態代理:使用了一個動態代理的方法來呼叫``LazyMap#get,原因是當我們呼叫某個動態代理物件的方法時,都會觸發代理類的invoke`方法,並傳遞對應的內容

分析一下利用過程:這裡1,2,3,4,5是一條利用鏈,邏輯很清晰。1,2,3,6,7是一條利用鏈。這裡還是比較繞的,分析一下利用過程:

只需要找到某個地方呼叫了LazyMap#get方法,並且傳遞了任意值。

首先在readObject時,會觸發AnnotationInvocationHandler#readObject方法,其中呼叫了this.memberValues.entrySet

this.memberValues是構造好的proxyMap,由於這是一個代理物件,所以呼叫其方法時,會去呼叫其建立代理時設定的handlerinvoke方法

proxyMap設定的handler為下面這個handler,同樣是InvocationHandler這個類,接著會呼叫他的invoke方法

InvocationHandler#invoke的78行程式碼中呼叫了this.memberValues#get,此時的this.memberValues為之前設定好的lazymap,所以這裡呼叫的是lazymap#get,從而觸發後邊的rce鏈。

代理後的物件叫做proxyMap,但我們不能直接對其進行序列化,因為我們入口點是 sun.reflect.annotation.AnnotationInvocationHandler#readObject ,所以我們還需要再用 AnnotationInvocationHandler對這個proxyMap進行包裹:

這裡還是比較繞的,因為設定了兩個handler,但是第一個handler是為了觸發lazymap#get,而第二個handler實際上只是為了觸發代理類所設定handler的invoke方法

接著解釋一些細節的問題:

  1. 為什麼這用反射的方式來建立AnnotationInvocationHandler的範例?

    因為AnnotationInvocationHandler並不是public類,所以無法直接通過new的方式來建立其範例。

2.為什麼建立handler時傳入的第一個引數是Retention.class?

因為在建立範例的時候對傳入的第一個引數呼叫了isAnnotation方法來判斷其是否為註解類:

 public boolean isAnnotation() {
        return (getModifiers() & ANNOTATION) != 0;
    }

而Retention.class正是java自帶的一個註解類,所以這裡可以直接用上,當然要是換成其他註解類也是ok的。

CC6

CommonsCollections1利用鏈,兩種方法,LazyMap以及TransformedMap,但是在Java 8u71以後,這個利⽤鏈不能再利⽤了,主要原因是 sun.reflect.annotation.AnnotationInvocationHandler#readObject的邏輯變化了

所以關注點如何調⽤LazyMap#get()

找到的類是org.apache.commons.collections.keyvalue.TiedMapEntry ,在其getValue⽅法中調⽤了 this.map.get,⽽其hashCode⽅法調⽤了getValue⽅法

又在 java.util.HashMap#readObject中就可以找到 HashMap#hash()的調⽤

/*
	Gadget chain:
	    java.io.ObjectInputStream.readObject()
          java.util.HashMap#readObject
                   java.util.HashMap#hash()
                    org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
                    org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
                        org.apache.commons.collections.map.LazyMap.get()
                            org.apache.commons.collections.functors.ChainedTransformer.transform()
                            org.apache.commons.collections.functors.InvokerTransformer.transform()
                            java.lang.reflect.Method.invoke()
                                java.lang.Runtime.exec()
*/

而ysoserial中使用HashSet.readObject()來呼叫

  java.util.HashSet.readObject()
                java.util.HashMap.put()
                java.util.HashMap.hash()

邏輯也很清晰

這條鏈是Java7和8高版本通殺

CC3

首先利⽤TemplatesImpl鏈是可以通過TemplatesImpl#newTransformer()執行程式碼的。

在一個為了繞過⼀些規則對InvokerTransformer的限制。所以CC3並沒有使⽤到InvokerTransformer來調⽤任意⽅法,⽽是⽤到了另⼀個 類, com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter

這個類的構造⽅法中調⽤(TransformerImpl) templates.newTransformer(),免去了我們使⽤InvokerTransformer⼿⼯調⽤newTransformer()⽅法這⼀步

⽤到⼀個新的Transformer,就是 org.apache.commons.collections.functors.InstantiateTransformerInstantiateTransformer也是⼀個實現了Transformer接⼝的類,他的作⽤就是調⽤構造⽅法.

利⽤InstantiateTransformer來調⽤到TrAXFilter的構造⽅法,再利⽤其構造⽅法⾥的templates.newTransformer()調⽤到TemplatesImpl⾥的位元組碼

小結

知識點比較多,每一個都捋清楚後,就可以重分發散思維,各種組合利用