FavoriteLoading
0

JXBrowser JavaScript-Java bridge 中的RCE漏洞

我近期正在研究如何使用JXBrowser来实现一套试验性的扫描技术。当我在使用JXBrowser库的过程中,我突然想到,是否可以通过调用不同的类来攻击JXBrowser客户端,并通过一个Web页面来实现远程代码执行呢?
安全客百科-JxBrowser
JxBrowser是一款采用Java语言开发的浏览器组件。JxBrowser能在Windows、Linux、Mac OS X (Intel和PPC-based)平台上将Mozilla Firefox浏览器完美地整合到Java AWT/Swing应用程序里。该库程序使用Gecko设计引擎来转换HTML文档。因而保证了它能与许多Internet标准(如HTML 4、CSS、XML、JavaScript以及其它)兼容。

漏洞利用技术分析
我编写的JavaScript代码(Java Bridge)大致如下:
browser.addScriptContextListener(new ScriptContextAdapter() {
@Override
public void onScriptContextCreated(ScriptContextEvent event) {
Browser browser = event.getBrowser();
JSValue window = browser.executeJavaScriptAndReturnValue("window");
window.asObject().setProperty("someObj", new someJavaClass());
}
});
上面这段示例代码是从JXBrowser网站上摘录下来的。大致来说,这段代码向浏览器实例中插入了一个脚本,然后获取到了window对象,并将其转换成了一个Java JSValue对象。接下来,代码在window对象中设置了“someObj”,然后将这个Java对象传递给JavaScript window对象,这样就设置好了我们的bridge(Java桥接模式)了!根据开发文档的描述,我们在这里只能使用公共类。当我们创建好了一个bridge之后,我们在与其交互的过程中还需要使用一些JavaScript脚本。
setTimeout(function f(){
if(window.someObj && typeof window.someObj.javaFunction === 'function') {
window.someObj.javaFunction("Called Java function from JavaScript");
} else {
setTimeout(f,0);
}
},0);
我在这里设置了超时(setTimeout),它可以检测我们是否已经获取到了这个“someObj”。如果没有检测到这个对象的话,代码会不断调用这个方法,直到检测到了这个对象为止。一开始,我曾尝试使用getRuntime()方法来查看我是否可以获取到一个runtime对象的实例,并运行calc(计算器)。。我所使用的调用代码如下所示:

window.someObj.getClass().forName('java.lang.Runtime').getRuntime();
但是,我得到了以下的错误返回信息:

Neither public field nor method named 'getRuntime' exists in the java.lang.Class Java object(Java对象java.lang.Class中不存在公共域或getRuntime方法)
难道是因为我们无法在这里调用getRuntime方法么?于是乎,我打算用更简单的方法来尝试一下,代码如下所示:

window.someObj.getClass().getSuperclass().getName();
这一次,我们的代码似乎成功运行了。接下来,我开始尝试枚举出所有可用的方法。代码和运行结果如下所示:
methods = window.someObj.getClass().getSuperclass().getMethods();
for(i=0;i
console.log(methods[i].getName());
}
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
大家可以看到,我成功地枚举出了所有的方法。接下来,我打算尝试使用一下ProcessBuilder,看看会发生什么。但是,当我每一次尝试调用构造器的时候,代码都崩溃了。根据报错信息来看,似乎构造器需要一个Java数组来作为输入。这也就意味着,我得想办法创建一个用来保存字符串的Java数组,然后将其传递给ProcessBuilder的构造器。
window.someObj.getClass().forName("java.lang.ProcessBuilder").newInstance("open","-a Calculator");
//Failed
window.someObj.getClass().forName("java.lang.ProcessBuilder").newInstance(["open","-a Calculator"]);
//Failed too
别着急,我们暂时先不管这个问题,先让我们创建另一个对象来证明这个漏洞的存在。我通过下面这段代码成功地创建了一个java.net.Socket类的实例。代码如下所示:

window.someObj.getClass().forName("java.net.Socket").newInstance();
但是,当我尝试调用这个对象的时候,我再一次遇到了问题,这一次系统返回的错误信息告诉我“参数类型发生错误”。虽然我现在可以创建socket对象,但是我却无法使用它们。由于我无法向该对象传递任何的参数,所以这个对象对于我来说暂时没有任何的意义,因为它根本无法使用。接下来,我又尝试去创建并使用java.io.File类的对象,但是我又失败了。我感觉现在已经走投无路了,我虽然可以创建出这些对象,但是每当这些函数需要我提供参数的时候,我都无法提供正确类型的参数值。不仅newInstance方法无法正常工作,而且其他的调用方法也无法正确运行。
柳暗花明又一村
我需要帮助,我非常迫切地需要Java大神的帮助!幸运的是,如果你在Portswigger这样的地方工作的话,你就会发现你永远不是实验室里最聪明的那个人。在我“走投无路”的时候,我便打算向Mike和Patrick寻求帮助。我把我现在遇到的问题向他们解释了一遍:我需要创建一个Java数组,然后将这个数组作为参数传递给函数方法。接下来,我们的工作重点就放在了如何在bridge中创建数组对象。
Mike认为,也许可以使用一个arraylist来实现我们的目标,因为我们可以通过toArray()这个简单的方法来将arraylist转换为一个数组(array)对象。

分页阅读: 1 2
【声明】:8090安全小组门户(http://www.8090-sec.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱hack@ddos.kim,我们会在最短的时间内进行处理。