BeanShell
BeanShell是一个小型的,免费的,可嵌入的Java源代码解释器,具有对象脚本语言功能,用Java编写。BeanShell动态地执行标准Java语法,并使用常见的脚本便利(如Perl和JavaScript中的松散类型、命令和方法闭包)对其进行扩展。
0x01 基本信息
通过以下 Demo 可以执行命令,解析一下 Demo 中各个部分的作用
public class Test {
public static void main(String[] args) throws Exception {
Interpreter interpreter = new Interpreter();
String func = "exec(Object cmd){java.lang.Runtime.getRuntime().exec(cmd);}";
interpreter.eval(func);
String payload = "exec(poc)";
interpreter.set("poc", "open -a Calculator.app");
interpreter.eval(payload);
}
}
bsh.Interpreter
bsh.Interpreter 是脚本解释器,提供了执行 BeanShell 脚本的功能,通过 eval() 方法用于执行给定的 BeanShell 表达式或语句。
bsh.NameSpace
set() 方法用于设置变量或属性值,保存在 bsh.NameSpace 中,这个变量用于管理解释器的变量、函数和类的命名空间。

0x02 bsh.This
而 bsh.NameSpace 和 bsh.Interpreter 共同构成 BeanShell 的上下文对象,用 bsh.This 类表示。
bsh.XThis 是其子类, invokeMethod() 方法提供了从脚本中调用方法的能力,上文的例子转化为通过 XThis 来执行如下:
Interpreter interpreter = new Interpreter();
String func = "exec(Object cmd){java.lang.Runtime.getRuntime().exec(cmd);}";
interpreter.eval(func);
XThis xThis = new XThis(interpreter.getNameSpace(), interpreter);
xThis.invokeMethod("exec", new Object[]{"open -a Calculator.app"});
bsh.XThis 又一个内部 Handler 类实现了动态代理,并且调用了 invokeImpl() 方法

而 invokeImpl() 方法中通过 invokeMethod() 执行了方法,所以与 Jython 的调用链类似,同样可以用 Comparator 来触发。

0x03 BeanShell1 user.dir 泄露
BeanShell1 这条调用链在生成时会泄露文件路径,参考这篇文章 https://mp.weixin.qq.com/s/CQ-jlcb3w72OP5UyGynMHg
在 Interpreter 对象初始化时,会调用 bsh.Interpreter.initRootSystemObject() 方法,将 user.dir 赋值给 bsh.cwd 属性,避免这个泄露需要反射修改该值
