從反射鏈的構(gòu)造看JAVA反序列化
http://www.freebuf.com/news/150872.html
構(gòu)造反射鏈:Transformer類(lèi),源碼解釋為從一個(gè)類(lèi)轉(zhuǎn)化為另一個(gè)類(lèi)。其中的transform()為執(zhí)行轉(zhuǎn)換方法。
ConstantTransformer,invokerTransformer,ChainedTransformer和TransformedMap繼承了Transformer類(lèi)。利用它們來(lái)構(gòu)造反序列化payload,原理為:
ConstantTransformer類(lèi)通過(guò)transform轉(zhuǎn)換得到內(nèi)部類(lèi)的對(duì)象類(lèi)型,如參數(shù)是Runtime.class時(shí),經(jīng)ConstantTransformer類(lèi)執(zhí)行后返回java.lang.Runtime
invokerTransformer類(lèi),通過(guò)反射創(chuàng)建新的對(duì)象實(shí)例。其中transform方法定義為:

這個(gè)transform(Object input) 中使用Java反射機(jī)制調(diào)用了input對(duì)象的一個(gè)方法,而該方法名是實(shí)例化InvokerTransformer類(lèi)時(shí)傳入的iMethodName成員變量:

也就是說(shuō)這段反射代碼中的調(diào)用的方法名和Class對(duì)象均可控。于是,我們可以構(gòu)造一個(gè)惡意的Transformer鏈,借用InvokerTransformer.transform()執(zhí)行任意命令。
method.invoke(input,iargs)意思是,執(zhí)行input對(duì)象的method方法,參數(shù)是iargs。
舉例:構(gòu)造一個(gè)對(duì)象,并且調(diào)用transform對(duì)象,如下圖所示:

查看method變量的值如下圖所示:

cls變量獲取到的是傳遞進(jìn)來(lái)的input的對(duì)象值,此處input傳遞的是Runtime的對(duì)象,下面兩行代碼要反射Runtime的getRuntime方法,iMethodName表示要得到的方法名稱(chēng),iParamTypes表示方法中所使用的參數(shù)類(lèi)型的數(shù)組。
執(zhí)行invoke方法,因?yàn)槭欠瓷鋑etRuntime()方法,參數(shù)為空,所以iArgs的值可以為空。成功的反射出了Runtime.getRuntime()的方法,然而如果要執(zhí)行任意代碼的化,還需要有exec代碼段,全部應(yīng)該是Runtime.getRuntime().exec(“calc.exe”)。
構(gòu)造payload
此時(shí)已經(jīng)獲得了GetRuntime()的Method對(duì)象,如果要執(zhí)行exec(“calc.exe”),還需要進(jìn)行一次invoke反射的過(guò)程,將GetRuntime()反射成對(duì)象,因?yàn)橹挥袑?duì)象才能調(diào)用exec函數(shù)。因此我們根據(jù)上面構(gòu)造出下面的代碼段,如下圖:

上圖中,構(gòu)造出tran2的方法,配置invoke的參數(shù)都為null,利用tran2.transform(run),反射invoke方法,過(guò)程與上文中一樣,此處直接看輸出了:

此處已經(jīng)是Runtime類(lèi)了,繼續(xù)構(gòu)造exec(“calc.exe”)代碼段,如下圖所示:

由此構(gòu)造成功payload。
以上是構(gòu)造反射鏈,執(zhí)行反射鏈用到ChainedTransformer。

利用for循環(huán),對(duì)傳入的transformers[i]運(yùn)行transform方法,就是把上文的步驟利用一個(gè)for循環(huán)整合在了一起。
現(xiàn)在我構(gòu)造一個(gè)以數(shù)組為主的反射鏈進(jìn)行彈窗,代碼段如下圖所示:

構(gòu)造出了chain方法之后,還需要調(diào)用transform方法,至于傳入的對(duì)象會(huì)被很快覆蓋掉,所以input的類(lèi)型可以任意。
TransformedMap類(lèi)
這個(gè)類(lèi)調(diào)用了ChainedTransformer類(lèi)中的transform方法。transform函數(shù)調(diào)用在TransformedMap類(lèi)的setvalue方法中。

只要我們控制valueTransformer的值為ChainTransformer對(duì)象就可以執(zhí)行反射鏈了,找到他的賦值地點(diǎn),如下圖所示:

當(dāng)TransformedMap內(nèi)的key 或者value發(fā)生變化時(shí),就會(huì)觸發(fā)相應(yīng)的Transformer的transform()方法。另外,還可以使用Transformer數(shù)組構(gòu)造成ChainedTransformer。當(dāng)觸發(fā)時(shí),ChainedTransformer可以按順序調(diào)用一系列的變換。
payload測(cè)試代碼:
InvokerTransformer.transform()執(zhí)行任意命令,測(cè)試代碼如下:

這樣,這段惡意代碼本質(zhì)上就是利用反射調(diào)用Runtime() 執(zhí)行了一段系統(tǒng)命令,作用等同于:

也就是說(shuō),一個(gè)精心構(gòu)造的TransformedMap,在其任意鍵值被修改時(shí),可以觸發(fā)變換,從而執(zhí)行任意命令。