Shiro-550
环境搭建
漏洞环境:https://github.com/Medicean/VulApps/tree/master/s/shiro/1
1 | docker pull medicean/vulapps:s_shiro_1 |
原理分析
环境启动后有这样一个实例页面
登陆时勾选RememberMe
登陆后会设置相应Cookie,其中一个字段rememberMe有一串数值
在登陆回调上打断点 org/apache/shiro/mgt/DefaultSecurityManager.class
,跟踪整个流程
当RememberMe设置项为True时,进入this.rememberIdentity
分支
在这一分支中,会将身份序列化,之后把它AES加密后保存在rememberMe中
跟进this.encrypt
这里的AES密钥默认情况下是固定值
如果不使用setCipherKey
设置,默认密钥的Base64编码值为kPH+bIxk5D2deZiIxcaaaA==
在设置RememberMe之后,即使不携带JSESSION_ID
,也能够完成身份认证
带好rememberMe即可,服务端会返回一个新的JSESSIONID
在这一过程中必然会涉及反序列化,如果用户在RememberMe中提供了恶意代码,就能够攻击服务器。继续跟代码,看一下反序列化的具体过程。
已知在反序列化过程中一定会使用密钥,将断点打在AbstractRememberMeManager
的各个方法上,携带RememberMe数据请求,最终触发断点,查看调用栈后决定从DefaultSecurityManager
入手开始跟进 org/apache/shiro/mgt/DefaultSecurityManager.class
具体处理逻辑在SimpleCookie.class
中
取到RememberMe的值并解码,之后从中还原出Principal
在这里进行反序列化
使用DefaultSerializer
进行反序列化
接下来只需要找到一条可用的gadget,就能够完成命令执行。在Shiro中默认会使用Commons-collections-3.2.1
,原生条件下直接利用会有些问题,但在这里找到一条优化后的Exploit(ysomap项目看起来不错,需要之后详细分析下),编译ysoserial需要jdk1.7
拿到payload之后,需要将其base64.decode之后再用AES加密,逻辑也很好写,直接在源码中挖出来即可:
1 | package com.fakestudio; |
丢到rememberMe中即可触发反序列化:
漏洞修复
Shiro-550的修复是去除了硬编码的默认密钥,由上述分析可知,只要知道了AES加密的密钥,就能够继续构造rememberMe的数据,依然能够进行反序列化。在GitHub进行搜索,可以找到很多硬编码的CipherKey,其中不乏一些用户广泛的开源库,一旦这些代码被其他用户使用,就会带来安全问题。例如:
一些利用工具会集成已经搜集到 的CipherKey,以求攻击成功率的最大化
参考
Shiro-721
TODO