基于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
原创
©著作权归作者所有:来自51CTO博客作者a52170494的原创作品,谢绝转载,否则将追究法律责任
![](https://ucenter.51cto.com/images/noavatar_middle.gif)
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
Java开发必读,谈谈对Spring IOC与AOP的理解
在Java后台开发中,Spring框架的IOC(控制反转)和AOP(面向切面编程)是两个非常重要的概念。
AOP spring System IOC -
简单谈谈JAVASCRIPT高级特性
js中没有class的概念,我们可以使用function来模拟。惰性载入函数,例如我们通常使用以下的js代码创建ajax
javascript 前端开发 免费源码 开源商城 -
简单谈谈contextlib的使用
简单谈谈contextlib的使用写在前面做这件事的原因:在看书的时候,我发现了有大佬们用contextlib管理上下文,真的很牛皮,但是百度了以下,每个大佬都
contextlib jupyterlab yield 上下文 python