本篇文章為大家展示了Weblogic反序列化遠程代碼執行漏洞的分析報告怎么寫,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
4月17日,國家信息安全漏洞共享平臺(CNVD)公開了Weblogic反序列化遠程代碼執行漏洞(CNVD-C-2019-48814)。由于在反序列化處理輸入信息的過程中存在缺陷,未經授權的攻擊者可以發送精心構造的惡意 HTTP 請求,利用該漏洞獲取服務器權限,實現遠程代碼執行。目前,POC已在野外公開(見參考鏈接)。官方緊急補?。–VE-2019-2725)已于4月26日發布,請受影響主機及時修復漏洞。
受影響版本
Oracle WebLogic Server 10.*
Oracle WebLogic Server 12.1.3
影響組件:
bea_wls9_async_response.war
wsat.war
二、漏洞分析
根據國家信息安全漏洞共享平臺(CNVD)漏洞公告,此漏洞存在于異步通訊服務,可通過訪問路徑/_async/AsyncResponseService,判斷不安全組件是否開啟。wls9_async_response.war包中的類由于使用注解方法調用了Weblogic原生處理Web服務的類,因此會受該漏洞影響:
為更好的理解漏洞成因,通過IDEA對WebLogic服務器遠程動態調試(因為需要跟進原生類中的方法,需要在IDEA中指定WebLogic安裝目錄中的JDK文件夾),在ProcessBuilder類中打下斷點,關鍵的調用棧過程如下所示:
調用棧非常深,下面解釋一下幾個關鍵的部分。首先是繼承自HttpServlet的BaseWSServlet類,其中的service方法主要用于處理HTTP請求及其響應,通過HTTP協議發送的請求包封裝在HttpServletRequest類的實例化對象var1中:
調用BaseWSServlet中定義的內部類AuthorizedInvoke的run()方法完成傳入HTTP對象的權限驗證過程:
若校驗成功,則進入到SoapProcessor類的process方法中,通過調用HttpServletRequest類實例化對象var1的getMethod()方法獲取HTTP請求類型,若為POST方法,則繼續處理請求:
HTTP請求發送至SoapProcessor類的handlePost方法中:
private void handlePost(BaseWSServlet var1, HttpServletRequest var2, HttpServletResponse var3) throws IOException {
assert var1.getPort() != null;
WsPort var4 = var1.getPort();
String var5 = var4.getWsdlPort().getBinding().getBindingType();
HttpServerTransport var6 = new HttpServerTransport(var2, var3);
WsSkel var7 = (WsSkel)var4.getEndpoint();
try {
Connection var8 = ConnectionFactory.instance().createServerConnection(var6, var5);
var7.invoke(var8, var4);
} catch (ConnectionException var9) {
this.sendError(var3, var9, "Failed to create connection");
} catch (Throwable var10) {
this.sendError(var3, var10, "Unknown error");
}
}
為方便后續分析工作進行,在此先簡單介紹一下SOAP協議內容及格式:SOAP(中文稱之為簡單對象訪問協議),用于在WEB上交換結構化和固化的信息,是Web Service三要素之一,可以和現存的許多因特網協議和格式結合使用。下圖展示SOAP消息封裝的標準格式:
BaseWSServlet類實例化對象var1封裝了基于HTTP協議的SOAP消息:
調用var1對象中定義的getPort()方法解析SOAP消息中的根元素Envelope(可把 XML 文檔定義為 SOAP 消息),獲取所調用服務的端口信息:
通過var4對象的getWsdlPort().getBinding().getBindingType()方法獲取當前SOAP協議規范版本信息:
并將HttpServletRequest類的var2對象及HttpServletResponse類的對象var3傳入到HttpServerTransport類構造函數中初始化實例對象var6統一處理后續HTTP請求及響應。
繼續調用var4對象中getEndpoint()方法完成對SOAP消息中根元素Envelope解析并讀取與其相關聯的xmlns:soap命名空間,其后分別完成對SOAP Header元素和Body元素解析工作:
跟進WsSkel類中定義的invoke()方法,其中完成了ServerDispatcher類實例化過程,并調用setWsPort()方法指定服務請求地址,進入調試器查看WsPort對象var2的屬性值,發現底層依靠HashMap數據結構保存請求服務的Address和URI,其中當前請求http://:7001/_async/AsyncResponseService服務:
在調試器中查看ServerDispatcher對象var5屬性值,發現methodName屬性中賦值了onAsyncDelivery方法名,在調用dispatch()方法時將調用上述服務中定義的該方法:
WorkAreaServerHandler類中的handleRequest()方法用于處理訪問請求,通過WlMessageContext對象var2獲取傳入的MessageContext,調用var2對象的getHeaders()方法獲取傳入SOAP消息的Header元素,并最終將該元素傳遞到WorkAreaHeader對象var4中,可以在調試器中清晰看到元素內容的賦值:
新建WorkContextMapInterceptor對象var5,在其receiveRequest()方法中讀入經WorkContextXmlInputAdapter適配器構造函數轉換過后的var4對象字節數組輸出流,經內部getMap() -> receiveRequest() -> readEntry() 方法處理后,將上述Content字段傳入至WorkContextXmlInputAdapter類的readUTF()方法中:
readUTF()方法中調用WorkContextXmlInputAdapter類私有成員變量xmlDecoder的readObject()方法讀取字節數組,經內部SAXParser類鏈式調用一系列解析器的parse()方法后,最終在com.sun.beans.ObjectHandler類定義的endElement()方法中完成XML文檔元素解析過程,獲取了有效類名oracle.toplink.internal.sessions.UnitOfWorkChangeSet:
在Security機制完成對類名權限校驗后,利用Java反射機制,通過元類定義的newInstance()方法實現上述類的實例化過程:
同樣通過反射包中的Constructor類調用構造器方法傳入字節數組,為上述實例對象賦初值:
UnitOfWorkChangeSet對象完成初始化過程后,使用ByteArrayInputStream對象接收經構造函數傳入的字節數組,再將ByteArrayInputStream對象byteIn轉換為ObjectInputStream對象objectIn,并直接調用了objectIn對象的readObject()方法。由于WebLogic安裝包中默認SDK為1.6版本,在JDK版本<=JDK7u21前提下存在Java原生類反序列化漏洞,使用ysoserial工具生成惡意序列化對象(以計算器程序為例),可在調試器中查看到當前所傳入的序列化對象:
經readObject()方法反序列化惡意對象后通過在ProcessBuilder類的start()方法斷點處查看command屬性,發現成功傳入“calc”字符串:
到此就完成了漏洞利用的全過程,下圖演示了漏洞利用效果,通過反序列化漏洞成功運行了計算器程序:
下面來分析下本次漏洞和以前所公布的CVE-2017-3506和CVE-2017-10271之間的關系,依舊從補丁diff著手,上述兩個補丁都是在weblogic/wsee/workarea/WorkContextXmlInputAdapter.java中添加了validate方法。首先來看CVE-2017-3506補丁文件,其實現方法簡單來說就是在調用startElement方法解析XML的過程中,如果解析到Element字段值為Object就拋出異常:
private void validate(InputStream is) { WebLogicSAXParserFactoryfactory = new WebLogicSAXParserFactory(); try { SAXParser parser =factory.newSAXParser(); parser.parse(is, newDefaultHandler() { public void startElement(String uri, StringlocalName, String qName, Attributes attributes) throws SAXException { if(qName.equalsIgnoreCase("object")) { throw newIllegalStateException("Invalid context type: object"); } } }); } catch(ParserConfigurationException var5) { throw newIllegalStateException("Parser Exception", var5); } catch (SAXExceptionvar6) { throw newIllegalStateException("Parser Exception", var6); } catch (IOExceptionvar7) { throw newIllegalStateException("Parser Exception", var7); } }
但上述這類采用黑名單的防護措施很快就被如下POC輕松繞過,因為其中不包含任何Object元素,但經XMLDecoder解析后依舊造成了遠程代碼執行:
<java version="1.4.0" class="java.beans.XMLDecoder"> <new class="java.lang.ProcessBuilder"> <string>calc</string><method name="start" /> </new></java>
針對如上所示一系列bypass CVE-2017-3506補丁限制的POC的產生,官方在同年十月份發布了CVE-2017-10271補丁文件。和上述不同點在于本次更新中官方將object、new、method關鍵字繼續加入到黑名單中,一旦解析XML元素過程中匹配到上述任意一個關鍵字就立即拋出運行時異常。但是針對void和array這兩個元素是有選擇性的拋異常,其中當解析到void元素后,還會進一步解析該元素中的屬性名,若沒有匹配上index關鍵字才會拋出異常。而針對array元素而言,在解析到該元素屬性名匹配class關鍵字的前提下,還會解析該屬性值,若沒有匹配上byte關鍵字,才會拋出運行時異常:
public void startElement(String uri, String localName, String qName, Attributesattributes) throws SAXException { if(qName.equalsIgnoreCase("object")) { throw newIllegalStateException("Invalid element qName:object"); } else if(qName.equalsIgnoreCase("new")) { throw newIllegalStateException("Invalid element qName:new"); } else if(qName.equalsIgnoreCase("method")) { throw newIllegalStateException("Invalid element qName:method"); } else { if(qName.equalsIgnoreCase("void")) { for(int attClass = 0; attClass < attributes.getLength();++attClass) { if(!"index".equalsIgnoreCase(attributes.getQName(attClass))){ throw newIllegalStateException("Invalid attribute for elementvoid:" + attributes.getQName(attClass)); } } } if(qName.equalsIgnoreCase("array")) { String var9 =attributes.getValue("class"); if(var9 != null &&!var9.equalsIgnoreCase("byte")) { throw newIllegalStateException("The value of class attribute is notvalid for array element."); }
本次反序列化漏洞繞過以往補丁的關鍵點在于利用了Class元素指定任意類名,因為CVE-2017-10271補丁限制了帶method屬性的void元素,所以不能調用指定的方法,而只能調用完成類實例化過程的構造方法。在尋找利用鏈的過程中發現UnitOfWorkChangeSet類構造方法中直接調用了JDK原生類中的readObject()方法,并且其構造方法的接收參數恰好是字節數組,這就滿足了上一個補丁中array標簽的class屬性值必須為byte的要求,再借助帶index屬性的void元素,完成向字節數組中賦值惡意序列化對象的過程,最終利用JDK 7u21反序列化漏洞造成了遠程代碼執行。通過巧妙的利用了void、array和Class這三個元素成功的打造了利用鏈,再次完美的繞過了CVE-2017-10271補丁限制,本次漏洞的發現進一步證明了依靠黑名單機制是一種不可靠的防護措施。
官方目前已發布針對此漏洞的緊急修復補丁,可以采取以下4種方式進行防護。
及時打上官方CVE-2019-2725補丁包
官方已于4月26日公布緊急補丁包,下載地址如下:https://www.oracle.com/technetwork/security-advisory/alert-cve-2019-2725-5466295.html?from=timeline
升級本地JDK版本
因為Weblogic所采用的是其安裝文件中默認1.6版本的JDK文件,屬于存在反序列化漏洞的JDK版本,因此升級到JDK7u21以上版本可以避免由于Java原生類反序列化漏洞造成的遠程代碼執行。
配置URL訪問控制策略
部署于公網的WebLogic服務器,可通過ACL禁止對/_async/*及/wls-wsat/*路徑的訪問。
刪除不安全文件
刪除wls9_async_response.war與wls-wsat.war文件及相關文件夾,并重啟Weblogic服務。具體文件路徑如下:
10.3.*版本:
12.1.3版本:
注:wls9_async_response.war及wls-wsat.war屬于一級應用包,對其進行移除或更名操作可能造成未知的后果,Oracle官方不建議對其進行此類操作。若在直接刪除此包的情況下應用出現問題,將無法得到Oracle產品部門的技術支持。請用戶自行進行影響評估,并對此文件進行備份后,再執行此操作。
上述內容就是Weblogic反序列化遠程代碼執行漏洞的分析報告怎么寫,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。