1. 项目概述:从“黑盒”到“白盒”的漏洞认知之旅
在安全研究领域,Shiro反序列化漏洞是一个绕不开的经典课题。它不仅仅是一个CVE编号,更是一个理解Java安全、框架设计缺陷和攻击者思维的绝佳样本。很多初学者拿到一个漏洞编号,比如CVE-2016-4437,第一反应往往是去网上找一份现成的利用脚本(POC),运行一下,看到回显的“whoami”就宣告复现成功。但这真的够了吗?在我看来,这仅仅是“黑盒”测试的起点。真正的价值在于“白盒”分析——深入代码层面,弄清楚漏洞为何会产生、攻击链是如何构造的、框架的防御机制又为何失效。这个过程,才是从“脚本小子”迈向“安全研究员”的关键一步。
“Shiro反序列化漏洞代码分析”这个项目,正是要带你走完这段旅程。它面向的是已经对Web安全基础(如HTTP、Cookie、Session)和Java Web开发有初步了解,不满足于单纯运行POC,渴望理解底层原理的开发者或安全爱好者。通过这个项目,你将不再被动地接受“这里有个漏洞”的结论,而是能够主动地、像侦探一样,顺着代码的逻辑线索,亲手揭开漏洞的神秘面纱。你会发现,那些看似复杂的攻击载荷(Payload),其设计思路在源码面前变得异常清晰;你也会明白,为什么某些版本的Shiro可以被打,而另一些则免疫,这背后的判断依据都写在代码里。
2. 漏洞背景与核心原理深度拆解
2.1 Shiro框架的“记忆”机制:RememberMe与序列化
要理解这个漏洞,必须先理解Shiro框架中的一个便利功能:RememberMe(记住我)。这是一个提升用户体验的常见设计,用户登录一次后,关闭浏览器再打开,无需重新输入密码即可保持登录状态。Shiro是如何实现这个“记忆”功能的呢?答案就是序列化(Serialization)。
序列化,简单来说,就是把一个内存中的Java对象,转换成一串可以存储或传输的字节流的过程。反序列化则是其逆过程,将这串字节流还原成内存中的对象。当用户勾选“记住我”并成功登录后,Shiro会做以下几件事:
- 将用户的身份信息(如用户名)、登录时间等,封装成一个
PrincipalCollection对象。 - 使用一个 固定的、硬编码在源码中的密钥(AES Key) ,对这个对象进行AES加密。
- 将加密后的字节流进行Base64编码。
- 将编码后的字符串,设置为名为
rememberMe的Cookie,发送给用户的浏览器。
当用户再次访问网站时,浏览器会自动带上这个Cookie。Shiro的过滤器会拦截请求,发现 rememberMe Cookie后,便执行反向操作:Base64解码 -> AES解密 -> 反序列化,还原出 PrincipalCollection 对象,从而自动完成登录认证。
注意 :这里埋下了第一个祸根—— 硬编码的默认密钥 。如果开发者在部署应用时没有修改这个密钥,那么所有使用该版本Shiro的应用,其加密密钥都是公开的。攻击者可以轻易地伪造或解密Cookie。
2.2 漏洞的“命门”:Java反序列化攻击链
问题的核心在于第三步:反序列化。Java的反序列化机制有一个特性:在将字节流还原为对象时,会自动调用该对象的 readObject() 方法。如果被反序列化的类重写了 readObject() 方法,那么该方法中的代码就会被执行。
攻击者的思路由此产生:我能否构造一个特殊的字节流,当Shiro试图反序列化它时,最终触发一段执行任意命令的代码?答案是肯定的,这依赖于“反序列化利用链”(Gadget Chain)。这条链由一系列存在于项目依赖库(如commons-collections, commons-beanutils)中的类组成,它们像多米诺骨牌一样,通过巧妙的属性设置和方法调用,最终可以触发命令执行(如 Runtime.getRuntime().exec(“calc”) )。
Apache Commons Collections 3.2.1版本中著名的 TransformedMap 、 InvokerTransformer 等类,就构成了这样一条经典的攻击链(通常称为CC链)。Shiro在反序列化时,并没有严格检查即将被反序列化的对象类型,它只是忠实地执行了 ObjectInputStream.readObject() </
366



被折叠的 条评论
为什么被折叠?



