(點擊上方公眾號,可快速關注)
來源:hengyunabc,
blog.csdn.net/hengyunabc/article/details/49804577
如有好文章投稿,請點擊 → 這裡了解詳情
新版apache commons collections 3.2.2修復漏洞
新版本的apache commons collections默認禁止了不安全的一些轉換類。可以通過升級來修復漏洞。參考release說明:https://commons.apache.org/proper/commons-collections/release_3_2_2.html
Dubbo rpc遠程代碼執行的例子
重新思考了下這個漏洞,給出一個dubbo rpc遠程代碼執行的例子。
https://github.com/hengyunabc/dubbo-apache-commons-collections-bug
可以說很多公司開放的rpc,只要協議裡支持Java序列化方式,classpath裡有apache commons collections的jar包,都存在被遠程代碼執行的風險。
至於能不能通過http接口再調用dubbo rpc遠程代碼,貌似不太可行。因為信息難以傳遞。
Apache Commons Collections遠程代碼執行漏洞
最近出來一個比較嚴重的漏洞,在使用了Apache Commons Collections的Java應用,可以遠程代碼執行。包括最新版的WebLogic、WebSphere、JBoss、Jenkins、OpenNMS這些大名鼎鼎的Java應用。
這個漏洞的嚴重的地方在於,即使你的代碼裡沒有使用到Apache Commons Collections裡的類,只要Java應用的Classpath裡有Apache Commons Collections的jar包,都可以遠程代碼執行。
參考:
這個漏洞的演示很簡單,只要在maven依賴裡增加
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
再執行下面的Java代碼:
Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class },
new Object[] { "getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class },
new Object[] { null, new Object[0] }),
new InvokerTransformer("exec", new Class[] { String.class }, new Object[] { "calc" }) };
Transformer transformedChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "value");
Map outerMap = TransformedMap.decorate(innerMap, null, transformedChain);
Map.Entry onlyElement = (Entry) outerMap.entrySet().iterator().next();
onlyElement.setValue("foobar");
這個漏洞的根本問題並不是Java序列化的問題,而是Apache Commons Collections允許鏈式的任意的類函數反射調用。攻擊者通過允許Java序列化協議的埠,把攻擊代碼上傳到伺服器上,再由Apache Commons Collections裡的TransformedMap來執行。
這裡不對這個漏洞多做展開,可以看上面的參考文章。
如何簡單的防止Java程序調用外部命令?
從這個漏洞,引發了很久之前的一個念頭:如何簡單的防止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裡。如果想禁止所有外部文件執行,可以在下面的配置文件中把execute 刪除:
grant {
permission java.io.FilePermission "<<ALL FILES>>", "read, write, delete, execute";
};
但是Java權限機制是白名單的,還有一大堆的權限要配置上去,非常複雜。
從tomcat的配置就知道了。http://tomcat.apache.org/tomcat-7.0-doc/security-manager-howto.html
所以Tomcat默認是沒有啟用Security Policy的,可以通過在命令加上-security參數來啟用。
catalina.sh start -security
那麼有沒有簡單的辦法可以在代碼裡禁止Java執行外部命令?
研究了下,通過擴展SecurityManager可以簡單實現:
SecurityManager originalSecurityManager = System.getSecurityManager();
if (originalSecurityManager == null) {
// 創建自己的SecurityManager
SecurityManager sm = new SecurityManager() {
private void check(Permission perm) {
// 禁止exec
if (perm instanceof java.io.FilePermission) {
String actions = perm.getActions();
if (actions != null && actions.contains("execute")) {
throw new SecurityException("execute denied!");
}
}
// 禁止設置新的SecurityManager,保護自己
if (perm instanceof java.lang.RuntimePermission) {
String name = perm.getName();
if (name != null && name.contains("setSecurityManager")) {
throw new SecurityException("System.setSecurityManager denied!");
}
}
}
@Override
public void checkPermission(Permission perm) {
check(perm);
}
@Override
public void checkPermission(Permission perm, Object context) {
check(perm);
}
};
System.setSecurityManager(sm);
}
只要在Java代碼裡簡單加上面那一段,就可以禁止執行外部程序了。
Java序列化的本身的蛋疼之處
其實Java自身的序列化機制就比較蛋疼,可以參考Effective Java裡的。
http://allenlsy.com/NOTES-of-Effective-Java-10/
並非禁止外部程序執行,Java程序就安全了
要注意的是,如果可以任意執行Java代碼,還可以做很多事情,比如寫入ssh密鑰,從而可以遠程登陸,參考最近的Redis未授權訪問漏洞:https://www.sebug.net/vuldb/ssvid-89715
總結
禁止JVM執行外部命令,是一個簡單有效的提高JVM安全性的辦法。但是以前沒有見到有相關的內容,有點奇怪。
可以考慮在代碼安全掃描時,加強對Runtime.exec相關代碼的檢測。
有些開源庫喜歡用Runtime.exec來執行命令獲取網卡mac等操作,個人表示相當的蛋疼,不會使用這樣子的代碼。
看完本文有收穫?請轉發分享給更多人
關注「ImportNew」,提升Java技能