Skip to content

Latest commit

 

History

History
61 lines (49 loc) · 3.97 KB

File metadata and controls

61 lines (49 loc) · 3.97 KB

修改 ShiroKey(ModifyShiroKey)

  • 类别:bytecode 别名:— 优先级:—
  • 作者:Ar3h
  • 依赖:无(产物为纯字节码,运行时依赖目标存在 Shiro)

作用

产出一段字节码,被目标 JVM 加载后会把 Apache Shiro 的 rememberMe AES 加密密钥(CipherKey)改成攻击者指定的值。用于「已知一个 gadget 能加载类、但不知道原 Shiro key」的场景:先把 key 改成自己可控的固定 key,之后即可用该 key 稳定构造 rememberMe Cookie 进行反序列化利用。是一个链尾字节码 sink(END)。

链接标签

  • 入口 tagsBytecodeEND —— Bytecode 表示产物是字节码 byte[]END 表示它是链终点(sink),其后不接任何 gadget。
  • 衔接 nextTags:空。
  • excludes:无。

需由上游「字节码装载器」承接(把 byte[] 变成被加载/执行的类),例如经 BytecodeConvert 装入 TemplatesImpl 后由 Java 反序列化跳板触发。

源码剖析

结构与其它 Bytecode sink 一致:取模板类 → 回填字段 → 导出字节码:

@GadgetTags(tags={"Bytecode", "END"})
@GadgetAnnotation(name="修改ShiroKey", description="修改 Shiro key 字节码", authors={"Ar3h"})
public class ModifyShiroKey implements Gadget {
    @Param(name="修改后的ShiroKey")
    public String key = "18yK12qfl0PRxrsW8zoXkg==";

    public byte[] getObject() throws Exception {
        JavassistHelper javassistHelper = new JavassistHelper(ModifyShiroKeyBytecode.class);
        javassistHelper.modifyStringField("key", this.key);
        return javassistHelper.getBytecode();
    }

    @Override
    public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
        chain.doCreate(context);
        return this.getObject();
    }
}

逐段解释:

  • 模板类:改 key 的真正逻辑固定在 com.ar3h.chains.gadget.impl.bytecode.common.template.ModifyShiroKeyBytecode 中——该类在被目标加载时,会反射定位 Shiro 的 CookieRememberMeManager(或其 AbstractRememberMeManager)并调用 setCipherKey(Base64.decode(key)) 把加密密钥替换为字段 key 的值。
  • 字段回填modifyStringField("key", this.key) 用 Javassist 直接改写模板类中 key 字段的常量初值,把攻击者的新 key(默认 18yK12qfl0PRxrsW8zoXkg==,即 Shiro 历史默认硬编码 key)写进字节码。
  • invoke:先 chain.doCreate(context),再 getObject() 返回改写后的 byte[]。本 gadget 只产出字节码,加载动作由上游装载器完成。

默认 key 18yK12qfl0PRxrsW8zoXkg== 恰是 Shiro < 1.2.4 泄露的默认密钥;把目标 key 强制改成它,等于把一个「未知 key 的目标」降级为「已知默认 key 的目标」,随后即可用公开工具直接打 Shiro 反序列化。

参数(@Param)

字段 名称 说明 默认 可选值
key 修改后的ShiroKey 目标 Shiro rememberMe 的 AES 密钥将被改成此值(Base64) 18yK12qfl0PRxrsW8zoXkg== 任意 Base64 编码的 16 字节密钥

适用版本与原理要点

  • 适用于目标运行 Apache Shiro 且已有一条能加载/执行任意类字节码的通道。
  • 本身不直接 RCE,而是把「密钥爆破/未知」问题转化为「密钥已知」,属于辅助性 sink。
  • 依赖模板类对 Shiro 内部 RememberMeManager/CipherKey API 的反射兼容性,Shiro 版本差异可能影响成功率。

所属预设链

usedInChains 为空——自由构件,未直接出现在 51 条预设链中。作为特化的字节码 sink,供 Shiro 场景按需替换普通 Exec sink。

关联

  • 上游(吃 Bytecode 的装载器):BytecodeConvertTemplatesImpl 等字节码装载跳板。
  • 同族(其它 bytecode/common 字节码 sink):以相同「模板类 + JavassistHelper.modifyStringField 回填」模式实现的各类载荷。