Skip to content

Latest commit

 

History

History
103 lines (76 loc) · 9.53 KB

File metadata and controls

103 lines (76 loc) · 9.53 KB

自定义字节码-Hex字符串(BytecodeFromHex)

  • 类别bytecode 别名:— 优先级:200
  • 作者:Ar3h
  • 实现Gadget(无基类;直接实现 com.ar3h.chains.common.Gadget
  • 依赖:无第三方 Maven 依赖(运行期用到工具自带的 org.apache.commons.codec.binary.HexJavassistHelper

作用

链尾的自定义字节码源:把用户提供的一段十六进制字符串(hexString)用 Hex.decodeHex 还原成原始 class 字节流,交由链上游的字节码加载器(典型为 TemplatesImpl + BytecodeConvert)装载执行。它相当于 Exec、各类回显/内存马 sink 的「万能替身」——不生成固定功能的恶意类,而是让使用者直接投喂任意自编译字节码,从而把 java-chains 的利用链变成一个纯粹的「字节码投递」通道,增强工具拓展性。

摘自 @GadgetAnnotation.description:从参数中解码获取字节码字节流,适用于自定义字节码场合,增加了工具拓展性。

与之完全同构的姊妹构件:BytecodeFromBase64(Base64 编码)、BytecodeFromLocalFile(本地文件)、BytecodeFromUploadFile(上传文件)——四者仅字节码来源不同,后续处理一致。

链接标签

  • 入口 tagsBytecodeConvertTagBytecodeEND —— 一个构件同时挂三种入口标签,使其可占据链上三种角色:
    • BytecodeConvertTag:可直接承接上游标注 nextTags=BytecodeConvertTag 的 gadget(如 TemplatesImpl),越过 BytecodeConvert 加工环,把 Hex 解码出的字节码原样递给加载器。
    • Bytecode:可承接上游 nextTags=Bytecode 的加工位(即接在 BytecodeConvert 之后),充当真正产出字节码的 sink,与 Exec/Sleep 同位。
    • END:可作为整条链的终结点——自身即产出最终字节码,无需更内层 gadget。
  • 衔接 nextTags:(空)—— 叶子节点,其后不再接任何 gadget。
  • excludes:(无)

源码剖析

全类仅 40 余行,核心是 getObject

@GadgetTags(tags={"BytecodeConvertTag", "Bytecode", "END"})
@GadgetAnnotation(name="自定义字节码-Hex字符串",
                  description="从参数中解码获取字节码字节流,适用于自定义字节码场合,增加了工具拓展性",
                  priority=200, authors={"Ar3h"})
public class BytecodeFromHex implements Gadget {
    @Param(name="十六进制字符串", description="会自动根据该字符串进行Hex解码获取字节码")
    public String hexString;

    public byte[] getObject(GadgetContext context) throws Exception {
        byte[] bytecode = Hex.decodeHex((String)this.hexString);        // ① Hex 解码为原始 class 字节
        JavassistHelper javassistHelper = new JavassistHelper(bytecode); // ② 用 Javassist 解析字节码
        context.put(ContextTag.CLASS_NAME_KEY, javassistHelper.getClassName()); // ③ 把类名写入上下文
        return javassistHelper.getBytecode();                            // ④ 返回(规范化后的)字节码
    }

    @Override
    public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
        chain.doCreate(context);        // 履行链契约:驱动内层(此处通常为空链,返回值被丢弃)
        return this.getObject(context); // 真正产物由本构件自身生成
    }
}

逐段解释:

  • Hex.decodeHex(this.hexString)hexString 是完全由使用者控制的攻击载荷——一段编译好的 Java class 文件的十六进制串。这里直接还原为 byte[] 原始字节码,没有任何形态校验或白名单,本构件不关心该类做什么。
  • new JavassistHelper(bytecode):把原始字节码交给工具内置的 JavassistHelper(Javassist CtClass 封装),解析出类结构。该工具类未随 CFR 反编译产物导出(属工具自身 util,不在 中),但从 BytecodeConvert 中对它的用法可知:它能读类名、改类名、设父类(AbstractTranslet)、调字节码版本、去符号、重新导出字节码等。此处只用到其中两项只读能力。
  • context.put(ContextTag.CLASS_NAME_KEY, javassistHelper.getClassName()):把从字节码里解析出的真实类名写进 GadgetContext。这一步是链协作的关键——上游加载器(TemplatesImpl/BytecodeConvert)需要知道即将 defineClass 的类名,才能正确实例化/触发它。构件之间通过 context 这一「黑板」传递此类元信息,实现松耦合的自由组合。
  • return javassistHelper.getBytecode():返回字节码。经 JavassistHelper 往返后是「规范化」后的字节,但因本构件未调用任何 handleXxx/setXxx,功能上等价于输入字节码。
  • invoke 中的 chain.doCreate(context):本构件是链尾字节码源,正常情况下 nextTags 为空、其后无内层 gadget,doCreate 对空链返回 null 且返回值被直接丢弃;调用它只是遵守 Gadget 接口「先构建内层」的契约,并允许任何被显式串在其后的内层 gadget 对 context 做副作用。真正的产物完全由本构件自身的 getObject 生成,这与「由内向外包装内层对象」的常规 gadget(如 CommonsBeanutils1)形成对比。

参数(@Param)

字段 名称 说明 类型 默认 可选值
hexString 十六进制字符串 会自动根据该字符串进行 Hex 解码获取字节码 String 无(必填)

使用者需自行准备一段编译好的恶意类字节码并转成十六进制串填入。若目标经由 TemplatesImpl 加载,该类通常需继承 AbstractTranslet(此步一般交给上游 BytecodeConvertneedAbstractTranslet 处理;直接经 BytecodeConvertTag 位使用时则需字节码自带该父类)。

适用版本与原理要点

  • 无版本/依赖约束Hex.decodeHex 属 commons-codec(工具已内置),JavassistHelper 为工具自带,构件本身不引入任何目标侧第三方依赖,故 dependencies 为空。
  • 能否落地取决于加载器:本构件只负责「产出字节码」,是否 RCE 取决于上游加载入口。经典组合是 TemplatesImpl → BytecodeConvert → BytecodeFromHex,要求目标 JDK 能通过 TemplatesImpl.newTransformer() 实例化 translet(JDK < 17 限制、需类继承 AbstractTranslet)。
  • 可跳过 BytecodeConvert:因携带 BytecodeConvertTag,可直接接在 TemplatesImpl 之后。此时不会自动改类名/设父类/去符号——字节码须自带加载器所需的一切(如已 extends AbstractTranslet),适合投递完全自制、已符合约束的字节码。
  • 拓展性定位:优先级 200(数值大、排序靠后),定位为高级/自定义场景,而非默认首选;意在给使用者一个不受工具内置 sink 功能限制的「任意字节码」出口。

所属预设链

usedInChains 为空——自由构件,未直接出现在 51 条预设链中。它按 tags/nextTags 与字节码加载器自由组合,典型用法是替换预设链尾部的 Exec 等固定 sink,例如把 [..., TemplatesImpl, BytecodeConvert, Exec] 改为 [..., TemplatesImpl, BytecodeConvert, BytecodeFromHex] 以投递自定义字节码。

关联

  • 姊妹构件(同 bytecode/common,仅字节码来源不同)BytecodeFromBase64BytecodeFromLocalFileBytecodeFromUploadFile
  • 上游加工位(nextTags=BytecodeBytecodeConvert——常见地在其后作为字节码源。
  • 上游加载器(nextTags=BytecodeConvertTagTemplatesImpl——可直连本构件的 BytecodeConvertTag 入口。
  • 功能同位的固定 sinkExecSleep 及各类 *Echo 回显 / 内存马 sink。

防御与检测

  • 检测特征
    • 反序列化流量中出现 TemplatesImplcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl)序列化指纹,其 _bytecodes 字段携带完整 class 字节(魔数 CAFEBABE / 十六进制 cafebabe)。
    • 运行期 ClassLoader.defineClass/TransletClassLoader.defineClass 被从 TemplatesImpl.getTransletInstance 调用栈触发,加载一个随机名、继承 AbstractTranslet 的类。
    • 该构件本身在攻击者侧留下超长十六进制字符串参数——但这仅存在于攻击者的 java-chains 客户端,不出现在受害流量中,故防守方应聚焦于字节码加载指纹而非 hex 串本身。
  • 加固建议
    • 反序列化输入实施类白名单(JEP 290 ObjectInputFilter),拒绝 TemplatesImplAbstractTranslet 及各 xsltc 类。
    • 关闭/隔离危险功能:禁用不必要的 XSLT/模板加载;对 defineClass 施加 RASP 拦截(拦截运行期由反序列化路径定义的、继承 AbstractTranslet 的类)。
    • 升级到不再允许 TemplatesImpl 反序列化实例化的 JDK(JDK 17+ 强模块封装显著抬高门槛)。
    • 网络层对入站序列化数据做 CAFEBABE 内嵌字节码扫描与告警。

参考

  • 反编译源码:
  • 机器可读元数据:index/gadgets.jsonclassName == "BytecodeFromHex"
  • 关联加工位剖析:BytecodeConvert