Shiro反序列化漏洞
什么是shiro反序列化漏洞
Shiro是Apache的一个强大且易用的Java安全框架,用于执行身份验证、授权、密码和会话管理。使用 Shiro 易于理解的 API,可以快速轻松地对应用程序进行保护
Shiro-550反序列化漏洞(CVE-2016-4437) 漏洞简介 shiro-550主要是由shiro的rememberMe内容反序列化导致的命令执行漏洞,造成的原因是默认加密密钥是硬编码在shiro源码中,任何有权访问源代码的人都可以知道默认加密密钥。 于是攻击者可以创建一个恶意对象,对其进行序列化、编码,然后将其作为cookie的rememberMe字段内容发送,Shiro 将对其解码和反序列化,导致服务器运行一些恶意代码。
环境搭建
我们先去github下载shiro 1.2.4的工程代码,下载链接如下
然后解压到一个文件夹,并打开shiro-shiro-root-1.2.4/pom.xml
文件,并把jstl依赖
版本改为1.2
然后使用IDEA打开Maven项目,位置选择我们刚才解压的文件夹,最后点击确认
然后IDAE会自动下载依赖项,需要等待一段时间,如果感觉下的很慢,或者下载失败的话,可以将Maven的下载源更改为国内的
下载完成后我们编辑下运行配置,设置为Tomcat本地服务器运行,然后JRE选择我们Java8版本的
然后点击部署,工件选择samples-web:war
最后点击运行即可,出现下面界面即代表配置成功
漏洞判断
访问url/samples_web_war/login.jsp
,并登陆抓包
抓包完成后,我们回到网页退出下登陆,然后在repeater界面重放下,可以看到remenberme 字段,代表可能存在shiro反序列化漏洞
当发现cookie中带有rememberMe字段时,就会触发getRememberedPrincipals方法
该方法路径为 org\apache\shiro\mgt\AbstractRememberMeManager.java 390行 getRememberedPrincipals
rememberMe解密流程
在shiro进行反序列化前会经过三层解密,如上图所示
1.getRememberedSerializedIdentity(subjectContext) //base64解密
2.convertBytesToPrincipals(bytes, subjectContext) //密钥aes解密&反序列化解密
2.1 decrypt(bytes) 密钥解密
2.2 deserialize(bytes)反序列化解密
接下来便对这三层解密进行分析
代码分析
第一层解密
在我们Cookie中传入代码如下rememberMe字段
后会先调用getRememberedPrincipals方法
对其处理,其中参数subjectContext
便是我们传入的rememberMe字段
我们看下该方法的代码
public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) {
PrincipalCollection principals = null;
try {
byte[] bytes = getRememberedSerializedIdentity(subjectContext);
//SHIRO-138 - only call convertBytesToPrincipals if bytes exist:
if (bytes != null && bytes.length > 0) {
principals = convertBytesToPrincipals(bytes, subjectContext);
}
} catch (RuntimeException re) {
principals = onRememberedPrincipalFailure(re, subjectContext);
}
return principals;
}
代码中的subjectContext属性
便为rememberMe字段
的值,我们发现对其调用了getRememberedSerializedIdentity方法
,跟进查看该方法代码如下
protected byte[] getRememberedSerializedIdentity(SubjectContext subjectContext) {
if (!WebUtils.isHttp(subjectContext)) {
if (log.isDebugEnabled()) {
String msg = "SubjectContext argument is not an HTTP-aware instance. This is required to obtain a " +
"servlet request and response in order to retrieve the rememberMe cookie. Returning " +
"immediately and ignoring rememberMe operation.";
log.debug(msg);
}
return null;
}
WebSubjectContext wsc = (WebSubjectContext) subjectContext;
if