🍬 博主介绍
👨🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~
✨主攻领域:【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】
🎉点赞➕评论➕收藏 == 养成习惯(一键三连)😋
🎉欢迎关注💗一起学习👍一起讨论⭐️一起进步📝文末有彩蛋
🙏作者水平有限,欢迎各位大佬指点,相互学习进步!
目录
0x1 前言
0x2 漏洞原理
0x3 漏洞分析
加密过程
解密过程
0x4 总结
0x1 前言
Shiro-550反序列化漏洞大约在2016年就被披露了,但感觉直到近一两年,在各种攻防演练中这个漏洞才真正走进了大家的视野,Shiro-550反序列化应该可以算是这一两年最好用的RCE漏洞之一,原因有很多:Shiro框架使用广泛,漏洞影响范围广;攻击payload经过AES加密,很多安全防护设备无法识别/拦截攻击……
shiro550基础环境的搭建,我是参照别的博客,这里给师傅们推荐下:
shiro-550 IDEA环境配置-CSDN博客
总结要下载的环境配置:
jdk1.8:https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html
tomcat8.5.99:https://tomcat.apache.org/download-80.cgi
shiro漏洞源码:https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4
这里给师傅们提示下,如果师傅们用的是开源版的idea,那么这里后面利用idea配置tomcat的时候,就会出问题,因为开源版的idea没有web功能,所以建议师傅们使用付给版的idea(因为我就是这莫过来的,很头大!!!)
这里给师傅们推荐下破解idea的文章:
Docs
环境搭建成功了之后,运行tomcat,浏览器就会自动弹出这个页面:
0x2 漏洞原理
根据漏洞描述,Shiro≤1.2.4版本默认使用CookieRememberMeManager,其处理cookie的流程是:
先获取cookie中的remberMe值 --> 对其base64解码 --> AES解码 --> 对解密的值反序列化
然而AES的密钥是硬编码的,就导致了攻击者可以构造恶意数据造成反序列化的RCE漏洞
payload 构造的顺序则就是相对的反着来:
构造恶意命令 --> 序列化 --> AES加密 --> base64编码 --> 发送cookie值
在整个漏洞利用过程中,比较重要的是AES加密的密钥,该秘钥默认是默认硬编码的,所以如果没有修改默认的密钥,就自己可以生成恶意构造的cookie了。
0x3 漏洞分析
加密过程
我们先进入登录界面,然后登录root用户,记得这里要勾选Remember Me 选项,然后利用burp抓包,需要注意的是,抓这个页面的POST包,因为还有一个GET包,但是这个GET包没有rememberMe 加密的字段。
注意看划重点的这几个地方,特别是rememberMe里面的加密内容
我们先打开idea,然后双击shift快捷键进行检索Cookie,然后找到跟CookieRememberMeManager有关的代码文件进行分析。
而我们看看这边CookieRememberMeManager
类继承了AbstractRememberMeManager
,我们在ctrl + B AbstractRememberMeManager
我们可以看到这边这个类里面有硬编码。
然后它又继承了RememberMeManager
接口,我们继续进去看看是怎么回事
点击分别查看这几个函数,知道这些是登陆成功,登陆失败,退出的一些service
我们再重新分析下代码文件:
在org/apache/shiro/mgt/DefaultSecurityManager.java代码的rememberMeSuccessfulLogin方法下断点
跟进onSuccessfulLogin方法,具体实现代码在AbstractRememberMeManager.java。
public void onSuccessfulLogin(Subject subject, AuthenticationToken token, AuthenticationInfo info) {
//always clear any previous identity:
forgetIdentity(subject);
//now save the new identity:
if (isRememberMe(token)) {
rememberIdentity(subject, token, info);
} else {
if (log.isDebugEnabled()) {
log.debug("AuthenticationToken did not indicate RememberMe is requested. " +
"RememberMe functionality will not be executed for corresponding account.");
}
}
}
调用forgetIdentity方法对subject进行处理,subject对象表示单个用户的状态和安全操作,包含认证、授权等。
继续跟进forgetIdentity方法,getCookie方法获取请求的cookie,接着会进入到removeFrom方法。
removeForm主要在response头部添加Set-Cookie: rememberMe=deleteMe
然后再回到onSuccessfulLogin方法中,如果设置rememberMe则进入rememberIdentity。
rememberIdentity方法代码中,调用convertPrincipalsToBytes对用户名进行处理。
protected void rememberIdentity(Subject subject, PrincipalCollection accountPrincipals) {
byte[] bytes = convertPrincipalsToBytes(accountPrincipals);
rememberSerializedIdentity(subject, bytes);
}
进入convertPrincipalsToBytes,调用serialize对用户名进行处理。
protected byte[] convertPrincipalsToBytes(PrincipalCollection principals) {
byte[] bytes = serialize(principals);
if (getCipherService() != null) {
bytes = encrypt(bytes);
}
return bytes;
}
跟进serialize方法来到org/apache/shiro/io/DefaultSerializer.java,很明显这里对用户名进行了序列化。
再回到convertPrincipalsToBytes,接着对序列化的数据进行加密,跟进encrypt方法。加密算法为AES,模式为CBC,填充算法为PKCS5Padding。
getEncryptionCipherKey获取加密的密钥,在AbstractRememberMeManager.java定义了默认的加密密钥为kPH+bIxk5D2deZiIxcaaaA==。
加密完成后,继续回到rememberIdentity,跟进rememberSerializedIdentity方法。
对加密的bytes进行base64编码,保存在cookie中。至此,加密的流程基本就分析完了。
解密过程
给大家参考下这位大佬的博客:
https://changxia3.com/2020/09/03/Shiro反序列化漏洞笔记一(原理篇)/
0x4 总结
从上面的分析可以知道,大体的漏洞触发流程为:
先获取cookie中的remberMe值 --> 对其base64解码 --> AES解码 --> 对解密的值反序列化
所以Shiro反序列化漏洞一个很关键的点就在于AES解密的密钥,攻击者需要知道密钥才能构造恶意的序列化数据。在Shiro≤1.2.4中默认密钥为kPH+bIxk5D2deZiIxcaaaA==。官方针对这个漏洞的修复方式是去掉了默认的Key,生成随机的Key。