- 类别:bytecode 别名:— 优先级:—
- 作者:4ra1n、Ar3h
- 依赖:内置 class-obf v1.9.1 字节码混淆
链中的字节码加工中间件:接收上游(Exec/Sleep/各类回显与内存马等字节码 sink)产出的原始类字节码,按需修改类名、设置父类(AbstractTranslet)、调整字节码版本、去符号信息、乃至整体混淆,再把加工后的字节码交给下游(如 TemplatesImpl)。几乎所有「加载字节码 → RCE/回显」的链都经过它。
- 入口
tags:BytecodeConvertTag—— 承接上游标注nextTags=BytecodeConvertTag的 gadget(典型为TemplatesImpl)。 - 衔接
nextTags:Bytecode—— 之后接一个真正产出字节码的 sink(tags=Bytecode,如Exec)。 - 位置:位于「字节码加载器(TemplatesImpl)」与「字节码源(Exec)」之间。
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
this.gadgetContext = context;
this.initTemplatesClazz(); // 选择 jdk / apache 版 TemplatesImpl 三件套并写入 context
Object object = context.get(ContextTag.NEED_ABSTRACTTRANSLATE_KET);
if (object != null) this.needAbstractTranslet = (Boolean) object; // 由 TemplatesImpl 置入
this.realClassName = (this.className == null || "".equals(this.className) || "random".equals(this.className))
? FileHelper.getRandomClassName() : this.className;
// 从 context 读取各种「包装」开关:javaWrapper / snakeyaml / groovy / charsetWrapper
...
context.put(ContextTag.CLASS_NAME_KEY, this.realClassName);
byte[] bytecode = (byte[]) chain.doCreate(context); // 取下游 sink 产出的原始字节码
this.javassistHelper = new JavassistHelper(bytecode);
this.commonJavassist(); // 核心加工
byte[] bytes = this.javassistHelper.getBytecode();
if (this.classObfSwitch) { // 可选:调用 class-obf 混淆
BaseConfig config = SafeYamlUtils.parseAs(this.classObfConfig, BaseConfig.class);
Result result = new ClassObf(config).run(bytes);
if (result.getMessage().equals("success")) bytes = result.getData();
}
return bytes;
}commonJavassist() 依据上下文开关逐项加工字节码:
public void commonJavassist() throws Exception {
if (this.needAbstractTranslet) this.javassistHelper.handleTemplatesImpl(this.abstractTranslet); // 关键:设父类 AbstractTranslet
if (this.snakeyaml) this.javassistHelper.handleSnakeYamlScriptEngineFactory(); // 实现 ScriptEngineFactory 接口
if (this.groovy) this.javassistHelper.handleFastjsonGroovyASTTransformation(); // 实现 ASTTransformation 接口
this.javassistHelper.setClassName(this.realClassName);
if (this.javaWrapper) this.javassistHelper.handleJavaWrapper(); // 加 public static void _main(String[])
if (this.addMainFunc) this.javassistHelper.handleMainFunction(); // 加 public static void main(String[])
if (this.charsetWrapper) this.javassistHelper.handleCharsetWrapper();
this.javassistHelper.setVersion(Integer.parseInt(this.version)); // 默认 50 = JDK6
if (this.shrink) { this.javassistHelper.setCompress(true); this.javassistHelper.shrinkBytes(); } // 去符号
}关键点:
needAbstractTranslet由上游TemplatesImpl通过context传入;为真时让恶意类继承AbstractTranslet,这是TemplatesImpl.newTransformer()能实例化它的前提。handleSnakeYamlScriptEngineFactory/handleFastjsonGroovyASTTransformation/handleCharsetWrapper等开关也由 context 驱动,使同一份字节码能适配 SnakeYaml、Fastjson-Groovy、charsets.jar 等不同加载入口——体现「构件自由组合」。- 默认
version=50(JDK6 字节码,兼容性最好);shrink=true去除源码文件名/行号/局部变量名等符号信息。 initTemplatesClazz()支持在 JDK 内置com.sun...xsltc与 Apacheorg.apache.xalan.xsltc两套TemplatesImpl/AbstractTranslet/TransformerFactoryImpl间切换(useJdkAT)。
| 字段 | 名称 | 说明 | 默认 |
|---|---|---|---|
className |
类名 | 可手动指定,random 为随机类名 |
random |
shrink |
去除字节码符号信息 | 去源码文件名/行号/局部变量名等,建议开启 | true |
needAbstractTranslet |
TemplatesImpl 利用链 | 字节码实现 AbstractTranslet;据链上下文自动设置 |
false |
useJdkAT |
使用 jdk 中的 AbstractTranslet 类 | true=JDK 内置;false=apache 包 |
true |
version |
字节码版本 | 52=JDK8, 51=JDK7, 50=JDK6(推荐), 49=JDK5(范围 45~60) | 50 |
addMainFunc |
静态 main 函数 | 额外添加 public static void main 并调用无参构造 |
false |
classObfSwitch |
[ClassObf] 字节码混淆主开关 | 手动开启后才用 class-obf 混淆 | false |
classObfConfig |
[ClassObf] 字节码混淆配置 | class-obf 的 YAML 配置 | 内置默认 |
出现在几乎所有「加载字节码」类预设链中,例如 CB1链、K1/K2/K3/K4 链、Fastjson 链、Jackson 链、命令执行、二次反序列化链、Xslt 代码执行、Spring Bean Xml、Hessian 各链等。
- 上游(
tags=…, nextTags=BytecodeConvertTag):TemplatesImpl、TransformerWithTemplatesImpl、JsConvert、ElConvert 等 - 下游(
tags=Bytecode):Exec、Sleep、各类*Echo回显与内存马 sink