天天看點

禁止JVM執行外部指令Runtime.exec -- 由Apache Commons Collections漏洞引發的思考

最近出來一個比較嚴重的漏洞,在使用了apache commons collections的java應用,可以遠端代碼執行。包括最新版的weblogic、websphere、jboss、jenkins、opennms這些大名鼎鼎的java應用。

這個漏洞的嚴重的地方在于,即使你的代碼裡沒有使用到apache commons collections裡的類,隻要java應用的classpath裡有apache commons collections的jar包,并且開放了允許java序列化協定的端口,都可以遠端代碼執行。

參考:

https://github.com/frohoff/ysoserial

http://blog.chaitin.com/2015-11-11_java_unserialize_rce/

這個漏洞的示範很簡單,隻要在maven依賴裡增加

再執行下面的java代碼:

這個漏洞的根本問題并不是java序列化的問題,而是apache commons collections允許鍊式的任意的類函數反射調用。攻擊者通過允許java序列化協定的端口,把攻擊代碼上傳到伺服器上,再由apache commons collections裡的transformedmap來執行。

這裡不對這個漏洞多做展開,可以看上面的參考文章。

從這個漏洞,引發了很久之前的一個念頭:**如何簡單的防止java程式調用外部指令?**

java相對來說安全性問題比較少。出現的一些問題大部分是利用反射,最終用runtime.exec(string cmd)函數來執行外部指令的。**如果可以禁止jvm執行外部指令,未知漏洞的危害性會大大降低,可以大大提高jvm的安全性。**

換而言之,就是如何禁止java執行runtime.exec(string cmd)之類的函數。

在java裡有一套security policy,但是實際上用的人比較少。因為配置起來太麻煩了。

http://docs.oracle.com/javase/8/docs/technotes/guides/security/policyfiles.html

http://docs.oracle.com/javase/8/docs/technotes/guides/security/permissions.html

http://docs.gigaspaces.com/xap102sec/java-security-policy-file.html 詳細的權限清單可以參考這個文檔

從文檔裡可以知道,java裡并沒有直接禁止rumtine.exec 函數執行的權限。

禁止檔案執行的權限在java.io.filepermission裡。如果想禁止所有外部檔案執行,可以在下面的配置檔案中把<code>execute</code>删除:

但是**java權限機制是白名單的**,還有一大堆的權限要配置上去,非常複雜。

從tomcat的配置就知道了。http://tomcat.apache.org/tomcat-7.0-doc/security-manager-howto.html

是以tomcat預設是沒有啟用security policy的,可以通過在指令加上-security參數來啟用。

那麼有沒有簡單的辦法可以在代碼裡禁止java執行外部指令?

研究了下,通過擴充securitymanager可以簡單實作:

隻要在java代碼裡簡單加上面那一段,就可以禁止執行外部程式了。

其實java自身的序列化機制就比較蛋疼,可以參考effective java裡的。

http://allenlsy.com/notes-of-effective-java-10/

要注意的是,如果可以任意執行java代碼,還可以做很多事情,比如寫入ssh密鑰,進而可以遠端登陸,參考最近的redis未授權通路漏洞:https://www.sebug.net/vuldb/ssvid-89715

禁止jvm執行外部指令,是一個簡單有效的提高jvm安全性的辦法。但是以前沒有見到有相關的内容,有點奇怪。

可以考慮在代碼安全掃描時,加強對runtime.exec相關代碼的檢測。在jvm層面對所有runtime.exec打日志。

有些開源庫喜歡用runtime.exec來執行指令擷取網卡mac等操作,個人表示相當的蛋疼,不會使用這樣子的代碼。