内容提要
ShiroAttack2 5.x 更新将 GUI 工具转为 CLI,并引入 AI 技能文件指导操作。文章分析 Shiro-550 漏洞持久原因(默认密钥、更换困难、利用便捷),详述 CLI 设计、JSON 输出、Gadget 链适配(如 BeanComparator 版本问题)及攻击流程。通过继承 TextArea 复用核心代码,支持密钥爆破、命令执行、内存马注入和密钥替换,强调版本同步与排错策略。
延伸解读
Shiro-550 漏洞为何持久
Shiro-550 漏洞自 2016 年披露至今仍可利用,并非因为漏洞本身高级,而是三个现实因素叠加:默认密钥硬编码在早期版本中,且被大量教程和脚手架代码复制;更换密钥涉及所有节点同步修改,存在兼容窗口,多数团队选择不动;利用工具化程度高,从手动构造 Payload 到 GUI 点选再到 CLI 嵌入脚本,利用成本不断降低,暴露面随之增大。
Skill 文件与文档的区别
Skill 文件不是给人读的文档,而是给 AI Agent 在运行时加载的指令文件。它通过 YAML frontmatter 定义触发词和边界,正文按 CLI 命令结构组织,重点不是罗列参数,而是告诉 AI 何时传参、传什么、出错怎么办。例如,-K 参数标注为必需,若缺失则需先爆破;-g 参数省略时自动探测。这种设计让 AI 能根据上下文自主决策,而非机械执行命令。
serialVersionUID 兼容性坑
BeanComparator 的 serialVersionUID 在 commons-beanutils 1.8.3 和 1.9.2 中不同,直接使用编译依赖的 1.9.2 类会导致目标为 1.8.3 时反序列化失败。5.x 通过 Javassist 动态修改 UID 并加载到独立 ClassLoader 解决,但 5.0.1 曾因写错 UID 值导致回归。这提醒开发者,涉及 UID 修改时不能依赖注释或记忆,应使用 javap 直接读取实际值。
CLI 复用 GUI 核心的设计
CLI 通过继承 TextArea 并利用 ControllersFactory 注册假 MainController,实现了对 AttackService 核心代码的零修改复用。这种设计避免了维护两套攻击逻辑,但依赖 JavaFX 线程初始化,且输出层通过 OutputSink 接口区分日志和原始输出,使命令结果可直接透传。这种“少改核心代码”的思路为后续扩展提供了便利。
Q&A
Shiro-550 漏洞为什么至今仍可利用?
Shiro-550 漏洞(CVE-2016-4437)至今仍可利用,主要因为三个原因:一是 Shiro 1.2.4 及之前版本在 CookieRememberMeManager 中硬编码了默认 AES Key(kPH+bIxk5D2deZiIxcaaaA==),且大量教程和脚手架代码一直沿用;二是更换 Key 需要所有节点同步修改,并存在兼容窗口,多数团队选择不动;三是利用工具化程度高,从 ysoserial 手动构造到 GUI 点选再到 CLI 脚本化,利用成本极低。
ShiroAttack2 5.x 的 CLI 是如何复用原有 GUI 核心代码的?
ShiroAttack2 5.x 通过继承 TextArea 类实现 CLI 复用。核心类 AttackService 深度依赖 JavaFX 的 TextArea 输出日志,CLI 通过继承 TextArea 创建 ConsoleTextArea,重写 appendText 方法将日志桥接到 CLI 输出。同时利用 ControllersFactory 全局注册表,在 CLI 启动时注入一个假的 MainController,其 logTextArea 等组件替换为 ConsoleTextArea,从而让 AttackService 无感知地输出到 CLI,无需修改核心代码。
ShiroAttack2 5.x 的 --json 参数有什么作用?
--json 参数将工具输出分为两条通道:以 { 开头的行是结构化 JSON 日志(如 {"level":"info","msg":"[++] 存在shiro框架!"}),AI 或脚本可以直接 JSON.parse 提取信息;不以 { 开头的行是命令的原始输出(如 whoami 的结果 root),可直接透传。这样便于自动化解析和集成。
ShiroAttack2 5.x 如何处理 BeanComparator 的 serialVersionUID 版本兼容问题?
ShiroAttack2 5.x 通过 Javassist 在运行时修改 BeanComparator 的 serialVersionUID 字段,并使用独立 ClassLoader 加载修改后的类,以适配不同版本的 commons-beanutils。例如,_183 后缀的 Gadget 会将 serialVersionUID 改为 1.8.3 对应的值(-3490850999041592962L),从而避免反序列化时因 UID 不匹配而抛出 InvalidClassException。
ShiroAttack2 5.x 的自动探测 Gadget 链时,为什么优先使用不依赖 commons-collections 的变体?
因为大多数目标只有 commons-beanutils 而没有 commons-collections,而 BeanComparator 的空构造器依赖 commons-collections 中的 ComparableComparator,如果目标缺少该依赖会抛出 UnknownClassException。因此,自动探测将不依赖 commons-collections 的变体(如 CommonsBeanutilsString、CommonsBeanutilsAttrCompare 等)排在前面,以提高探测成功率。
ShiroAttack2 5.x 中 AES 模式(CBC/GCM)是如何自动切换的?
Shiro 1.2.4 及之前使用 AES-CBC,1.2.5 开始使用 AES-GCM。5.0.2 开始 Key 验证会同时尝试 CBC 和 GCM,但早期版本在日志标注 GCM 后,AttackService.aesGcmCipherType 未同步更新,导致后续 Gadget 测试仍用 CBC。5.1.0 在 Key 爆破回调中补上了设置 aesGcmCipherType 的代码,使得爆破命中 GCM Key 后,后续操作自动使用 GCM 模式。
ShiroAttack2 5.x 中 jEG 和 jMG 生成器的作用是什么?
jEG(回显生成器)和 jMG(内存马生成器)是第三方生成器,ShiroAttack2 5.0 将其作为适配器接入,优先使用它们生成回显和内存马字节码,失败时回退到 Legacy 方式。jMG 支持的 Shell 类型从 2 种扩展到 5 种(Filter、Servlet、Interceptor、HandlerMethod、TomcatValve),适配 Tomcat 和 Spring MVC。这样新增中间件版本时只需更新 libs 下的 JAR,无需修改核心代码。
ShiroAttack2 5.x 中替换 Shiro Key 的六条路径是什么?
替换 Shiro Key 本质是注入一个 Filter 来修改 CookieRememberMeManager 的 cipherKey。六条路径包括:1. 标准 Spring 环境通过 ApplicationContext → shiroFilterFactoryBean → filterConfigs → RememberMeManager;2. Bean 名对不上时降级扫描 FilterChain 中名字含 'shiro' 的;3. 模糊匹配类名和配置中含 rememberMeManager 字段的;4. 遍历所有 Filter 修改(高风险,可能多个实例);5. 注入后自动用新旧 Key 验证;6. 不同部署环境选择不同路径。
ShiroAttack2 5.x 中请求头处理有哪些细节?
5.0 早期版本先设单次请求头再盖全局头,可能导致全局 Authorization 覆盖命令执行请求中的 Authorization,5.0.1 修复了顺序。Cookie 采用合并而非覆盖,确保业务 Cookie(如 JSESSIONID)和攻击 Cookie(rememberMe)同时存在。同时做了 Cookie 归一化,合并大小写变体,兼容不同容器的解析差异。
ShiroAttack2 5.x 中遇到 'Key 命中但所有链 deleteMe' 时应该怎么排查?
根据排错速查表,如果 Key 命中但所有链都返回 deleteMe,应检查 Key 的模式标注,手动指定模式(--cbc 或 --gcm)或升级到 5.1.0 版本,因为 5.1.0 修复了 GCM 模式未同步的问题。