shiro550反序列化分析
拖了很久的shiro分析
漏洞概述
Apache Shiro <= 1.2.4 版本中,加密的用户信息序列化后存储在Cookie的rememberMe字段中,攻击者可以使用Shiro的AES加密算法的默认密钥来构造恶意的Cookie rememberMe值,发送到Shiro服务端之后会先后进行Base64解码、AES解密、readObject()反序列化,从而触发Java原生反序列化漏洞,进而实现RCE。
该漏洞的根源在于硬编码Key。
漏洞复现
使用shiroattack工具

Dnslog接收到请求

执行命令

漏洞分析
远程调试
用idea连vulhub的docker环境来进行调试
首先进入容器
docker exec -it 34db756dfcfc /bin/bash
可以看到是用jar包起的环境,把文件拷贝出来(也可以docker-compose up -d之后使用docker ps --no-trunc来查看容器默认的启动命令)

docker cp 34db756dfcfc:/shirodemo-1.0-SNAPSHOT.jar ~/
然后把jar包解压了之后用idea打开

libraries里导入

在module中添加BOOT_INF这个目录

另外还需要改一下dockerfile
idea远程调试docker
需要增加一组端口供调试用,这里我们用idea默认的5005
vulhub的shiro环境是java -jar xxx.jar的形式运行的,那么添加对jar程序启动的调试命令即可,在启动docker时用自定义的COMMAND替换默认的COMMAND
version: '2'
services:
 web:
   image: vulhub/shiro:1.2.4
   ports:
    - "8080:8080"
    - "5005:5005"
   command: java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar /shirodemo-1.0-SNAPSHOT.jar
然后配置好remote

下好断点,输入登录账户密码测试,看到以下界面说明成功了

原理分析
从官方的 issue 上来看,存在几个重要的点:
- rememberMe cookie
 - CookieRememberMeManager.java
 - Base64
 - AES
 - 加密密钥硬编码
 - Java serialization
 
首先正常登录

返回的cookie值中的rememberme值如下:
o5NA+QAjgJpe6uKkIJ1li/WLqOAR2KfLIY3BzwfAUFbbkBSEfs3/259i4Qc2jq6lxUpLabYK2c0oR4faB3l8m0GDhzMvVYjFOR2TPKRtQmqlUAdaiJT06biAC56EMu6UbBJAujAgP1msHuJYkV1fDuhdLN5wGK+IlEpr1Xf+aa6oNkPqBkRG7+B/3bXQNTqmLFlarZUWxB6TwZyshplhx0ckyIfc0qJuf/f5Tt60gK/D28JUI93Gp3vGi/P7UUiwv2Qyzpz4hXZSUocGlC73qE+62ZvQ1ryzVRjpfTkG4Hat6sst04wbpFwdUSJxh6t4FLJ2i9bs5eIm/1UJpVHP9Eia5WaAShQa45qr5yIMA+q1rYxtz0WufvOi67fpqY3qi8LQ/ZnGwXUY+o6dLu2qmqHwTXbRTRKP4G5d3e5SA9FNvXUhYWRhcwo2zJ2lS2JK/D6S0u3HAak04+3wpbZm0UCJxafXlaFPUDhmiXBtIULcEELqBOaqLr1n7LV+F1Cl7kYNU6GozLVPvNlqW5UtLA==
跟一下登录生成cookie的过程
生成cookie
shiro会提供rememberme功能,可以通过cookie记录登录用户,从而记录登录用户的身份认证信息,即下次无需登录即可访问。而其中对rememberme的cookie做了加密处理,漏洞主要原因是加密的AES密钥是硬编码在文件中的,那么对于AES加密算法我们已知密钥,并且IV为cookie进行base64解码后的前16个字节,因此我们可以构造任意的可控序列化payload。
处理rememberme的cookie的类为org.apache.shiro.web.mgt.CookieRememberMeManager

它继承自org.apache.shiro.mgt.AbstractRememberMeManager,其中在AbstractRememberMeManager中定义了加密cookie所需要使用的密钥,当我们成功登录时,如果勾选了rememberme选项,那么此时将进入onSuccessfulLogin方法

之后进入serialize,对登录认证信息进行序列化

然后进行加密

org.apache.shiro.mgt.AbstractRememberMeManager中的encrypt方法如下
protected byte[] encrypt(byte[] serialized) {
    byte[] value = serialized;
    CipherService cipherService = getCipherService();
    if (cipherService != null) {
        ByteSource byteSource = cipherService.encrypt(serialized, getEncryptionCipherKey());
        value = byteSource.getBytes();
    }
    return value;
}
ByteSource byteSource = cipherService.encrypt(serialized, getEncryptionCipherKey());调用的即为AES算法

可以看到使用CBC模式的AES加密算法,其中Padding规则是PKCS5。
具体实现在org/apache/shiro/crypto/JcaCipherService.java中
private ByteSource encrypt(byte[] plaintext, byte[] key, byte[] iv, boolean prependIv) throws CryptoException {
    final int MODE = javax.crypto.Cipher.ENCRYPT_MODE;
    byte[] output;
    if (prependIv && iv != null && iv.length > 0) {
        byte[] encrypted = crypt(plaintext, key, iv, MODE);
        output = new byte[iv.length + encrypted.length];
        //now copy the iv bytes + encrypted bytes into one output array:
        // iv bytes:
        System.arraycopy(iv, 0, output, 0, iv.length);
        // + encrypted bytes:
        System.arraycopy(encrypted, 0, output, iv.length, encrypted.length);
    } else {
        output = crypt(plaintext, key, iv, MODE);
    }
    if (log.isTraceEnabled()) {
        log.trace("Incoming plaintext of size " + (plaintext != null ? plaintext.length : 0) + ".  Ciphertext " +
                "byte array is size " + (output != null ? output.length : 0));
    }
    return ByteSource.Util.bytes(output);
}
IV(初始化向量)是随机生成的,将IV放在crtpt()加密的数据之前然后返回
加密结束后,在org/apache/shiro/web/mgt/CookieRememberMeManager.java的rememberSerializedIdentity方法中进行base64编码,并通过response返回

这里的byte是前16位随机的IV+AES密文,然后经过base64编码

解析cookie
org/apache/shiro/web/mgt/CookieRememberMeManager.java中会将传递的base64字符串进行解码后放到字节数组中,因为java的序列化字符串即为字节数组
byte[] decoded = Base64.decode(base64);
然后进入解密流程

先解密后进行反序列化


AES是对称加密,加解密密钥都是相同的,并且shiro都是将密钥硬编码
public void setCipherKey(byte[] cipherKey) {
    //Since this method should only be used in symmetric ciphers
    //(where the enc and dec keys are the same), set it on both:
    setEncryptionCipherKey(cipherKey);
    setDecryptionCipherKey(cipherKey);
}
public AbstractRememberMeManager() {
    this.serializer = new DefaultSerializer<PrincipalCollection>();
    this.cipherService = new AesCipherService();
    setCipherKey(DEFAULT_CIPHER_KEY_BYTES);
}
在org/apache/shiro/crypto/JcaCipherService.java的decrypt()方法中进行解密从cookie中取出iv与加密的序列化数据

调用crypt方法利用密文,key,iv进行解密

解密完成后进入反序列化,看上面的public AbstractRememberMeManager()这里用的是默认反序列化类
public T deserialize(byte[] serialized) throws SerializationException {
    if (serialized == null) {
        String msg = "argument cannot be null.";
        throw new IllegalArgumentException(msg);
    }
    ByteArrayInputStream bais = new ByteArrayInputStream(serialized);
    BufferedInputStream bis = new BufferedInputStream(bais);
    try {
        ObjectInputStream ois = new ClassResolvingObjectInputStream(bis);
        @SuppressWarnings({"unchecked"})
        T deserialized = (T) ois.readObject();
        ois.close();
        return deserialized;
    } catch (Exception e) {
        String msg = "Unable to deserialze argument byte array.";
        throw new SerializationException(msg, e);
    }
}

readobject()触发反序列化
至此,Shiro对Cookie的rememberMe的处理流程已整体调试分析结束。
漏洞修复
Apache Shiro 1.2.5版本的源码,修复方法就是将使用默认Key加密改为生成随机的Key加密:https://github.com/apache/shiro/commit/4d5bb000a7f3c02d8960b32e694a565c95976848

参考
https://ares-x.com/2020/04/20/IDEA远程调试Docker中程序的方法/
https://paper.seebug.org/shiro-rememberme-1-2-4/
https://xz.aliyun.com/t/6493?accounttraceid=052d6170a05a4736a42c47de607a2766sdut#toc-6
https://www.mi1k7ea.com/2020/10/03/浅析Shiro-rememberMe反序列化漏洞(Shiro550)/
shiro550反序列化分析的更多相关文章
- fastjson及其反序列化分析--TemplatesImpl
		
fastjson及其反序列化分析 源码取自 https://www.github.com/ZH3FENG/PoCs-fastjson1241 参考 (23条消息) Json详解以及fastjson使用 ...
 - [JavaWeb]反序列化分析(二)--CommonCollections1
		
反序列化分析(二)--CommonCollections1 链子分析 首先新建一个TransformedMap,其中二三参数为可控,后续要用到 当TransformedMap执行put方法时,会分别执 ...
 - Java安全之SnakeYaml反序列化分析
		
Java安全之SnakeYaml反序列化分析 目录 Java安全之SnakeYaml反序列化分析 写在前面 SnakeYaml简介 SnakeYaml序列化与反序列化 常用方法 序列化 反序列化 Sn ...
 - weblogic之CVE-2016-0638反序列化分析
		
此漏洞是基于CVE-2015-4852漏洞进行黑名单的绕过,CVE-2015-4852补丁主要应用在三个位置上 weblogic.rjvm.InboundMsgAbbrev.class :: Serv ...
 - shiro<1.2.4反序列化分析
		
0x01.环境搭建 下载地址:https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4 环境:Tomcat 8.5.27 + idea ...
 - weblogic之CVE-2016-3510反序列化分析
		
将反序列化的对象封装进了weblogic.corba.utils.MarshalledObject,然后再对MarshalledObject进行序列化,生成payload字节码.由于Marshalle ...
 - Java安全之Shiro 550反序列化漏洞分析
		
Java安全之Shiro 550反序列化漏洞分析 首发自安全客:Java安全之Shiro 550反序列化漏洞分析 0x00 前言 在近些时间基本都能在一些渗透或者是攻防演练中看到Shiro的身影,也是 ...
 - PHP反序列化总结
		
之前遇到过很多次php反序列化相关的内容,总结一下. (反)序列化给我们传递对象提供了一种简单的方法.serialize()将一个对象转换成一个字符串,unserialize()将字符串还原为一个对象 ...
 - shiro反序列化550、721
		
shiro550反序列化 获取docker镜像 docker pull medicean/vulapps:s_shiro_1 重启docker systemctl restart docker 启动d ...
 
随机推荐
- Jmeter压力测试学习7--压测带token的接口
			
前言 工作中我们需要压测的接口大部分都是需要先登陆后,带着token的接口(或者带着cookies),我们可以先登陆获取token再关联到下个接口.比如我现在要压测一个修改用户的个人的密码 场景案例 ...
 - MySQL表空间回收的正确姿势
			
不知道大家有没有遇到这样的一种情况,线上业务在MySQL表上做增删改查操作,随着时间的推移,表里面的数据越来越多,表数据文件越来越大,数据库占用的空间自然也逐渐增长 为了缩小磁盘上表数据文件占用的空间 ...
 - 记typora美化----让文章更加优美
			
前言 昨晚偶然间看到一篇介绍记笔记工具以及如何美化的视频,突发奇想我打算也写一篇记录一下自己的美化过程,并会把自己使用的插件,样式文件等提供在下方,觉得不错得可以直接拿去使用,只希望观众能够一键3连, ...
 - DOC命令和批处理命令
			
本文章以极简的方式展现,相信能够浏览到这篇文章的人都对批命令有了一定的了解,我不会把文章写的长篇大论 重要!!! (命令/?)查看帮助文档 (命令/help)查看详细帮助文档 附:思维导图 批处理编程 ...
 - v-for为什么最好(一定)要加key
			
v-for 指令基于一个数组来渲染一个列表,如下 1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> ...
 - 3.3 Execution Flow of a DDD Based Application 基于DDD的应用程序执行流程
			
3.3 Execution Flow of a DDD Based Application 基于DDD的应用程序执行流程 The figure below shows a typical reques ...
 - SpringBoot打包到docker(idea+传统方式)
			
作者:故事我忘了¢个人微信公众号:程序猿的月光宝盒 目录 1. 方式1.通过idea 远程发布 1.1 修改docker.service文件 1. 进入服务器 2. 修改ExecStart行为下面内容 ...
 - 【UE4】GAMES101 图形学作业1:mvp 模型、视图、投影变换
			
总览 到目前为止,我们已经学习了如何使用矩阵变换来排列二维或三维空间中的对象.所以现在是时候通过实现一些简单的变换矩阵来获得一些实际经验了.在接下来的三次作业中,我们将要求你去模拟一个基于CPU 的光 ...
 - 【UE4 C++】调用外部链接库 lib静态库
			
简述 本例以插件形式测试 使用Lib引用,打包程序运行不用再拷贝lib文件 需要 lib 文件和 .h 头文件 lib部分的代码 .h 头文件 #pragma once #ifndef __MYTES ...
 - 【二食堂】Beta - Scrum Meeting 12
			
Scrum Meeting 12 例会时间:5.27 20:00~20:10 进度情况 组员 当前进度 今日任务 李健 1. 知识图谱导出功能完成 issue 1. 继续完成文本保存的工作 issue ...
 
			
		