基於Java Exploit在漏洞研究領域越來越重要的地位,在下本着拋磚引玉的態度,寫下了這篇文章,希望對大家瞭解Java Exploit能有一定幫助。
2. 網頁中的Java
目前主要有兩種方式在網頁中啓動Java代碼: Applet和Java Web Launch。其中Java Web Launch是Java 1.5之後新加入的,而Applet則是早就存在。
記得當年學校教Java的時候,最後大作業就是寫一個功能複雜的Applet。不過現在Applet已經不流行了
在Html里加入如下代碼就可以嵌入Applet:
代碼:
<APPLET CODE="HelloWorldApplet.class" WIDTH=200 HEIGHT=100> </APPLET>
或者如果打包成jar的話:
代碼:
<APPLET archive=”HelloWorldApplet.jar” CODE="HelloWorldApplet.class" WIDTH=200 HEIGHT=100> </APPLET>
和Applet相對的,Java Web Launch用來從web上啓動Java Application。需要遵循Java Network Launch Protocol (jnlp)。
3.安全性和Sandbox
看到這裏,大家可能會想,既然我們可以隨意地在html中調用Java小程序,而Java語言的功能又非常強大,那直接寫個包含惡意代碼的Java小程序放到網上,不就相當於掛馬了嗎?
比如,你可能會想寫下如下代碼:
代碼:
import java.awt.*;import java.applet.*;import java.io.*;public class HelloWorldApplet extends Applet { public void init() { try { Runtime.getRuntime().exec("calc.exe"); } catch (IOException e) { e.printStackTrace(); } } public void paint(Graphics g ) { g.drawString("Hello World!",5,35); }}
然後在自己的網頁中加入如下代碼調用這個applet:
代碼:
<APPLET CODE="HelloWorldApplet.class" WIDTH=200 HEIGHT=100> </APPLET>
接着把網頁掛到某個服務器上,開始守株待兔,
呃,出錯了,我們得到了一個AccessControlException,提示沒有權限。
其實Java的設計者早就考慮了安全問題,並提出了Sandbox的概念。
簡單來講這個sandbox的意思就是:Java虛擬機在執行所有系統資源相關的操作(讀寫文件,運行命令,網絡通信。。。)時,都會檢查當前代碼是否有權限來進行這些操作,如果沒有權限,就會拋出異常。
整個Sandbox機制非常複雜,無法用很短的篇幅講清楚,下面只介紹一些要點:
1. 在Java虛擬機中運行的代碼,有受信任(Trusted Code)代碼和不被信任代碼(Untrusted Code)之分。
默認情況下,Java自帶的庫中的代碼都是受信任的代碼,而來自其他地方(比如來自網絡)的代碼是不受信任的。受信任代碼默認可以對任何系統資源進行操作而不受限制,而不受信任的代碼權限很低。
比如我們前面這個例子,由於HelloWorldApplet.class的代碼來自於網絡上,因此它是不受信任的代碼。
於是在試圖創建進程(ProcessBuilder.start()函數)時,Java虛擬機檢查到當前的代碼不受信任,於是拋出一個權限異常。
我們可以通過定義一些手段來讓自己的代碼受信任(比如添加Policy,代碼簽名等等)。
2. 在Java虛擬機進行權限檢查時,會檢查整個調用棧上的代碼,而不是隻檢查當前函數(這裏會有一些例外,如doPrivilaged和AccessControlContext,暫時可以忽略之)。
整個調用棧上只要有任何一個調用來自不受信任的代碼,就判定爲沒有權限。
還是上面這個例子,當最終檢查權限時,調用棧如下:
代碼:
Java.AccessControlContext.checkPermission (信任代碼)Java.AccessController.checkPermission (信任代碼)Java.SecurityManager.checkPermission (信任代碼)Java.SecurityManager.checkExec (信任代碼)Java.lang.ProcessBuilder.start (信任代碼)Java.lang.Runtime.exec (信任代碼)Java.lang.Runtime.exec (信任代碼)Java.lang.Runtime.exec (信任代碼)HelloWorldApplet.init (非信任代碼)sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run (信任代碼)Java.lang.Thread.Run (信任代碼)
用於我們自己的HelloWorldApplet代碼是不受信任的,於是整個檢查失敗,異常被拋出。
3. 權限檢查代碼是穿插在相關的Java API裏面的,還是我們上面的例子, Runtime.exec調用了ProcessBuilder.start,代碼如下:
代碼:
public Process start() throws IOException { // Must convert to array first -- a malicious user-supplied // list might try to circumvent the security check. String[] cmdarray = command.toArray(new String[command.size()]); cmdarray = cmdarray.clone(); for (String arg : cmdarray) if (arg == null) throw new NullPointerException(); // Throws IndexOutOfBoundsException if command is empty String prog = cmdarray[0]; SecurityManager security = System.getSecurityManager(); if (security != null) security.checkExec(prog); String dir = directory == null ? null : directory.toString(); try { return ProcessImpl.start(cmdarray, environment, dir, redirects, redirectErrorStream); } catch (IOException e) { // It's much easier for us to create a high-quality error // message than the low-level C code which found the problem. throw new IOException( "Cannot run program \"" + prog + "\"" + (dir == null ? "" : " (in directory \"" + dir + "\")") + ": " + e.getMessage(), e); } }}
注意裏面的SecurityManager.checkExec就是權限檢查代碼了。
SecurityManager是Java安全機制的核心,一個運行中的Java Virtual Machine可以有SecurityManager,也可以沒有,但是一旦設置了SecurityManager就不能再更改。
如果沒有SecurityManager,很多權限檢查都不會發生。如果在本地運行一個Java程序,默認是沒有SecurityManager的,
但是如果是通過瀏覽器啓動一個Applet,那相應的瀏覽器是一定會設置一個SecurityManager。
4.幾種類型的Java Exploit
通過前面的介紹,我們知道由於Sandbox機制的保護,正常情況下是不能用Java程序掛馬做壞事的,於是Java Exploit要做的事情就很明顯了:突破Java Sandbox的保護機制。
設想一下我們現在被關在一個封閉的房子裏,想要逃出去,那麼我們可能可以有兩種思路:
1.直接把牆給砸了。 2.找找看房子裏面有沒有沒關嚴實的門窗,或者地道什麼的。
在已有的Java漏洞中,第一種方法對應於那些針對Java虛擬機實現(主要是包括運行庫)和插件進行exploit的漏洞,典型的有CVE-2009-3867,CVE-2009-3869,CVE-2010-3552,CVE-2010-0886等。
這類漏洞的主要思想是:Java程序雖然運行在虛擬機中,但是整個虛擬機(包括運行時庫)的實現需要平臺相關的本地代碼來支撐(在windows上,就有諸如awt.dll,java.dll等本地代碼)。
如果這些代碼中存在漏洞,並且可以通過java代碼來觸發,我們就可以利用這些漏洞來運行shellcode,此時Sandbox機制就無能爲力了(因爲Sandbox針對的是Java代碼)。
我們來看一個例子,CVE-2009-3867。這是一個棧溢出漏洞,存在於Java MidiSystem類的getSoundbank函數中
我們可以通過傳一個超長的URL來觸發這個漏洞,請看代碼:
代碼:
String str1 = repeat(‘/’, 30200);MidiSystem.getSoundbank(new URL(str1));
Java運行庫中的一個strcpy操作引發了這個漏洞:
非常典型的棧溢出,大家可以自己調試一下。
值得注意的是如果通過IE瀏覽訪問exploit並調試,IE在隔了一段時間得不到響應後會終止Java虛擬機,可以通過在IE的Terminate Process上下斷來防止Java被關閉。
第二種突破Java Sandbox的方法是“繞”:
用Sandbox來保障安全的想法是非常好的,但是人非聖賢,孰能無過,真正到了代碼實現的時候,開發Java的大牛們還是偶爾會出一些小差錯,導致在某些情況下Sandbox機制可以被繞過。
典型的有CVE-2010-0840 和前幾天的CVE-2011-3554。
我個人感覺比起第一類“暴力***Java虛擬機”的漏洞,這類漏洞的危害更大一點。
因爲***者不需要費勁心思考慮如何讓自己的exploit變得穩定,不需要考慮煩人的DEP和ASLR,只要寫一段做壞事的Java代碼就好了。
下面看一下CVE-2010-0840:
大牛的blog已經講的非常詳細了:
http://slightlyrandombrokenthoughts....-cve-2010.html
我這邊總結一下,這個漏洞的核心思想如下:
前面提到過,當Java Sandbox權限檢查時,會檢查整個棧上的代碼,只要有任何非信任的代碼,檢查就失敗。
而CVE-2010-0840通過構造一個表達式(Expression),該表達式將執行setSecurityManager(null)來關閉Sandbox的安全機制。
調用setSecurityManager將觸發權限檢查,因此如果在我們自己的代碼中直接執行這個表達式是沒有權限的。
但是通過將這個表達式加入一個JList容器,讓Applet的UI線程來執行這個表達式,則可以做到權限檢查時,整個調用棧上都是Java自己的受信任庫代碼。於是成功繞過的Java Sandbox。
5.總結
終於寫完了,希望本文能幫助大家瞭解一些Java安全的相關知識
簡單談談Java Exploit
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章
Filter
矮油不錯哦_ab60
2019-02-24 14:12:49
Spring中你可能不知道的事(二)
CoderBear
2019-02-24 14:10:43
Spring中你可能不知道的事(一)
CoderBear
2019-02-24 14:10:42
三種方式實現觀察者模式 及 Spring中的事件編程模型
CoderBear
2019-02-24 14:10:42
C#中爲什麼會出現空靜態構造方法的寫法
CoderBear
2019-02-24 14:10:42
劍指Spring源碼(一)
CoderBear
2019-02-24 14:10:42
劍指Spring源碼(二)
CoderBear
2019-02-24 14:10:42
有點深度的聊聊JDK動態代理
CoderBear
2019-02-24 14:10:42
簡單的單例模式其實也不簡單
CoderBear
2019-02-24 14:10:42
Volatile的那些事
CoderBear
2019-02-24 14:10:42
【蛻變之路】第6天 面向對象 (2019年2月24號)
仵寧飛
2019-02-24 13:54:39
最新阿里Java技術面試題,看這一文就夠了!
_年少無爲
2019-02-24 13:27:21
Java面試學問多,看看高級程序員面試題是什麼樣的
_年少無爲
2019-02-24 13:27:21