前言
shiro是java的一个框架。在shiro框架中提供了一个rememberMe的功能,使用这个功能会在cookie中生成一个rememberMe的值。在验证登录时,shiro框架会验证cookie中rememberMe的值来验证登录。处理cookie值的过程大致是:获取rememberMe的值>base64解码>AES解密>反序列化。而且这个AES的密钥是硬编码,一般是默认的,因此产生了这个漏洞。
这篇文章主要记录我学习这个漏洞的过程。
一、shiro环境搭建
1、使用git下载原码,并使用checkout切换到1.2.4版本
2、使用idea打开代码,打开shiro/samples/web/pom.xml,将jstl版本改为1.2
3、tomcat部署
4、下载maven依赖项
到这里环境的部署就完成了。
二、Idea debug调试
在正式开始调试前,我先记录以下我学到的一些调试的模块。
1、debug模式和断点
首先要进行debug调试,肯定得使用debug模式
还有一个重要的点就是断点
打上断点后可以是代码运行到断点处停止,项图上红色菱形上有一个勾说明断点生效。
2、debug的一些按键
按键顺序按照从左到右
按键 | 功能 |
---|---|
步过 | 点击步过不会进入方法中 |
步入 | 点击步入会进入自定义的方法中 |
强制步入 | 点击强制步入会进入所有方法中 |
步出 | 点击步出返回到方法调用处 |
丢帧 | 回退断点 |
运行到光标处 | 程序运行到光标处 |
三、shiro debug调试
生成cookie过程
首先正常运行程序,使用bp抓包
可以看到有remeberMe的值,接下来具体看一下这个值是怎么生成的
在shiro/core/src/main/java/org/apache/shiro/mgt/RememberMeManager.java的第71行打上断点
跟进rememberIdentity方法
继续跟进rememberIdentity方法
接下来进入加密方法中看一下具体的加密过程
在这里可以看到对于获取到的信息先进行了序列化、后进行了加密,继续跟进加密方法
可以看到是一个AES加密,我们可以看一下AES的密钥是如何获得的
进入getEncryptionCipherKey方法中,然后网上找可以看到代码中的密钥,这个密钥很重要,是能否进行反序列化漏洞利用的关键。
我们接下来继续跟进程序
可以看到AES加密后进行了base64加密,最后系那个这个值放到了cookie中。
到这里整个生成cookie的过程就很明朗了,先是rememberMe功能拿到了登录信息,经过序列化>AES加密>base64加密这一系列过程生成了cookie值。
验证cookie过程
首先我们先在shiro/core/src/main/java/org/apache/shiro/mgt/DefaultSecurityManager.java的600行打上断点
然后通过bp发送一个cookie的值
代码来到rmm.getRememberPrincipals方法,跟进这个方法
可以看到以下这个方法,应该是获取序列化后的认证信息的,也就是rememberMe的值
跟进这个方法,在这个方法中可以跟清晰的看到,通过getcookie方法获取cookie值,然后对这个值进行了base64解码,最后返回这个值。
然后是进入这个方法,看方法名大概是对得到的byte值进行解密,跟进这个方法
可以看到这里主要有步,第一步是对其进行解密,我们知道是AES解密,第二步是反序列化,我们先跟进到解密方法
可以看到具体的一个解密过程,和加密过程差不多。AES是对称加密,因此加密密钥和解密密钥是一样的。
然后跟进反序列化方法
继续跟进
这一行方法是java读取对象,在这一步执行了我们写在cookie中的命令。
到这里为止是shiro框架读取到cookie中的rememberMe的之后验证的一系列过程。
四、漏洞的利用
使用shiro attack工具
可以看到密码可以爆破出,但是找不到构造链。源文件中使用的依赖是commons-collections:3.2.1,工具中没有可以使用的利用链。我们自己做可以将依赖版本换成4.0,不过再真实环境中是无法替换的。
总结
这是我学习使用debug方法调试的第一个漏洞,还存在很多的不足之处,请各位读者见谅。