Shiro-550反序列化漏洞

## Shiro-550反序列化漏洞

### 一、前置知识

#### 1.1 Shiro简介        

​        Apache Shiro 是一个强大易用的 Java 安全框架,提供了认证、授权、加密和会话管理等功能,对于任何一个应用程序,Shiro 都可以提供全面的安全管理服务。

![image-20220621160129969](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220621160137.png)

Primary Cocnerns(基本关注点):

- Authentication(认证):经常和登录挂钩,是证明用户说他们是谁的一个工作
- Authorization(授权):访问控制的过程,即,决定‘谁’可以访问‘什么
- Session Management(会话管理):管理用户特定的会话,即使在非web或是EJB的应用中
- Crytography(加密):通过加密算法保证数据的安全,且易于使用

Supporting Features(辅助特性):

- Web Support(网络支持):web support API可以帮助在web应用中方便的使用shiro
- Caching(缓存):保证安全操作使用快速有效
- Concurrency(并发):支持多线程应用
- Testing(测试):支持集成单元测试
- Run As(以..运行):可以假定用户为另一个用户
- Remeber Me:记住用户,无需再次登录

#### 1.2 Shiro服务器端识别身份加解密处理cookie的流程

##### 1.2.1 加密

1. 用户使用账号密码进行登录,并勾选”Remember Me“。

2. Shiro验证用户登录信息,通过后,查看用户是否勾选了”Remember Me“。

3. 若勾选,则将用户身份序列化,并将序列化后的内容进行AES加密,再使用base64编码。
4. 最后将处理好的内容放于cookie中的rememberMe字段。

##### 1.2.2 解密

1. 当服务端收到来自未经身份验证的用户的请求时,会在客户端发送请求中的cookie中获取rememberMe字段内容。
2. 将获取到的rememberMe字段进行base64解码,再使用AES解密。

3. 最后将解密的内容进行反序列化,获取到用户身份。

### 二、Shiro-550

#### 2.1 漏洞简介

​        shiro-550主要是由shiro的rememberMe内容反序列化导致的命令执行漏洞,造成的原因是默认加密密钥是硬编码在shiro源码中,任何有权访问源代码的人都可以知道默认加密密钥。于是攻击者可以创建一个恶意对象,对其进行序列化、编码,然后将其作为cookie的rememberMe字段内容发送,Shiro 将对其解码和反序列化,导致服务器运行一些恶意代码。

影响版本:shiro <= 1.2.4

特征:

1. cookie中含有rememberMe字段,如:“rememberMe=JV+gEljeMVBj3EFY22otzX......”

2. cookie中含有”rememberMe=delete“

#### 2.2  漏洞分析

##### 2.2.1 环境搭建

Shiro安装包:shiro-root-1.2.4(https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4)

调试环境:Tomcat 9.0.22 + idea 2022.2 + jdk 1.8 + maven 3.6,需要修改samples-web\pom.xml

```XML
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
    <scope>runtime</scope>
</dependency>
```

##### 2.2.2 加密过程分析

访问http://localhost:8080/samples-web/login.jsp,使用其提供的root用户登录,并勾选“Remember Me” 。

![image-20220622151011796](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622151011.png)

将断点放于AbstractShiroFilter.class中的doFilterInternal()方法处,会创建subject对象,并使用请求信息。

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622101941.png" alt="image-20220622101941000" style="zoom: 67%;" />

而后进行一些处理,会调用AuthenticatingFilter.class中的executeLogin()方对用户输入的登录信息进行验证,该方法会生成一个用于身份验证的token并进行相关验证。

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622102935.png" alt="image-20220622102934978" style="zoom:67%;" />

验证通过后返回后续需要的相关登录信息,而后继续跟进到DefaultSecurityManager.class的rememberMeSuccess()方法。此方法会获取RememberMeManager,若该对象不为空,则使用onSuccessfulLogin()方法处理传入的登录相关的信息(subject、token、info)。

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622104408.png" alt="image-20220622104408212" style="zoom:67%;" />

跟进到AbstractRememberMeManager.class的onSuccessfulLogin()方法,其首先会调用forgetIdentity()方法处理subject对象。

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622104543.png" alt="image-20220622104543777" style="zoom: 80%;" />

继续查看CookieRememberMeManager.class的forgetIdentity()方法,该方法取出了subject对象中的request与response交由另一个forgetIdentity()方法处理。

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622105054.png" alt="image-20220622105054884" style="zoom: 80%;" />

跟进另一个forgetIdentity()方法,其调用了removeFrom()方法来处理cookie。

![image-20220622105139033](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622105139.png)

来到SimpleCookie.class,removeFrom()方法获取相关信息(rememberMe字段及其值deleteMe,路径等),并将相关信息使用addCookieHeader()方法添加至cookie中。

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622105441.png" alt="image-20220622105441671" style="zoom:67%;" />

回到AbstractRememberMeManager.class的onSuccessfulLogin()方法,接着这里判断用户是否勾选了”Remember Me“ ,若是,则使用rememberIdentity()方法继续处理登录的相关信息。

![image-20220622105607728](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622105607.png)

在rememberIdentity()方法中,取出对应用户的身份验证信息(如这里的root)并生成一个principals对象来存放,而后再交由另一个rememberIdentity()方法进行处理。

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622150655.png" alt="image-20220622150655344" style="zoom:80%;" />

查看该rememberIdentity()方法,其调用了convertPrincipalsToBytes()方法来处理这个principals对象。convertPrincipalsToBytes()方法将principals对象进行序列化操作并用byte数组存放,判断是否启用加密服务,启用则将序列化的数据使用encrypt()方法进行加密。

![image-20220622110946822](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622110946.png)

跟进到encrypt()方法,其使用cipherService(生成的加密服务对象)的encrypt()方法将序列化数据进行加密,而加密方式AES加密,模式为CBC,密钥为128位(16个字节),填充方式为PKCS5Padding。

![image-20220622111812322](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622111812.png)

而其使用getEncryptionCipherKey()方法获取encryptionCipherKey用于加密的密钥。

![image-20220622111859207](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622111859.png)

其中用于加密的encryptionCipherKey与解密的decryptionCipherKey都是通过setCipherKey()方法来设置。

![image-20220622120529764](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622120529.png)

而该类的构造方法就调用了setCipherKey()方法设置为DEFAULT_CIPHER_KEY_BYTES,而这个默认的加密密钥就硬编码于代码中。

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622120633.png" alt="image-20220622120633676" style="zoom: 67%;" />

继续跟进到JcaChipherService的encrypt()方法,定义了一个ivBytes变量(CBC模式的初始化向量,用于每次AES加密之前或者解密之后,使用初始化向量与明文或密文异或),是随机生成的16个字节组成的字节数组。接着调用另一个encrypt()方法,并传入相关数据(plaintext:序列化数据,key: DEFAULT_CIPHER_KEY_BYTES,iv:随机生成的16个字节)

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622112817.png" alt="image-20220622112817327" style="zoom: 80%;" />

在这个encrypt()方法中主要有以下操作:

1. 调用AES的加密方法crypt(),将身份验证对象的序列化内容使用默认的密钥进行加密。
2. 生成一个用于存放输出值的byte数组output。
3. 将iv与encrypted放于output中。

最后将output返回。

![image-20220622114657382](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622114657.png)

而后回到AbstractRememberMeManager.class的rememberIdentity()方法,其接着调用了rememberSerializedIdentity()方法,将前面的output(iv变量与加密后的内容)进行base64编码,并将最终结果放于cookie中。

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622113327.png" alt="image-20220622113327849" style="zoom:80%;" />

##### 2.2.3 解密过程分析

勾选“Remember Me”进行登录后,进行调试,刷新页面。

将断点打在DefaultSecurityManager.class的第二个createSubject()方法处,该方法用于获取cookie中的rememberMe字段,并利用其生成subject对象。

![image-20220622165022157](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622165022.png)

我们单步进入resolvePrincipals()方法,其调用了getRememberedIdentity()方法去获取rememberMe中的身份信息。

![image-20220622165349981](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622165350.png)

getRememberedIdentity()方法中,其又调用了getRememberedPrincipals()方法。

![image-20220622165625290](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622165625.png)

跟进到AbstractRememberMeManager.class中的getRememberedPrincipals()方法,其先调用了getRememberedSerializedIdentity(),判断获取的值不为空后,又使用convertBytesToPrincipals()方法来获取用于身份验证的principals对象。

![image-20220622165817364](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622165817.png)

先看CookieRememberMeManager.class的getRememberedSerializedIdentity()方法,先获取cookie中的值,然后base64解码,返回解码后的数据。

![image-20220622170543238](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622170543.png)

接着查看convertBytesToPrincipals()方法,该方法调用了deserialize()方法进行反序列化操作。

![image-20220622170656928](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622170656.png)

跟进到DefaultSerializer.calss的deserialize()方法,发现其没有对传入的序列化数据做任何过滤,直接调用了ObjectInputStream的readObject()方法进行反序列化操作,从而使得可以利用该方法触发Apache Commons Collections链的反序列化漏洞。

![image-20220622170859697](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220622170859.png)

后续就是成功生成用于身份验证的对象,用户获取到权限进行访问。

#### 2.3 漏洞复现

##### 2.3.1 实验环境

被攻击主机

​    主机:Centos7.9 (IP:192.168.219.206)

​    漏洞环境:vulhub/shiro:1.2.4

攻击主机

​    主机:Windows10(IP:192.168.219.1)

​    漏洞利用工具:ShiroExploit by 飞鸿(https://github.com/feihong-cs/ShiroExploit-Deprecated),netcat-win32-1.12(https://eternallybored.org/misc/netcat/)

​    

##### 2.3.2 环境搭建

本次实验使用docker进行环境搭建。

1.拉取镜像

```
docker pull vulhub/shiro:1.2.4
```

2.创建容器

```
docker run -itd --name shiro550 -p 8080:8080 vulhub/shiro:1.2.4
```

3.临时开放端口

```
firewall-cmd --add-port=8080/tcp 
```

成功搭建后访问http://192.168.219.206:8080/,如下:

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220623094157.png" alt="image-20220623094150165" style="zoom: 33%;" />

##### 2.3.4 复现过程

在攻击主机打开shiro反序列化利用工具,选择漏洞类型为shiro550,地址栏中填入对应的地址,http://192.168.219.206:8080/

![image-20220623110154367](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220623110154.png)

而后选择ceye.io进行漏洞检测(CEYE是一个用于检测带外数据(Out-of-Band)的监控平台,例如DNS查询和HTTP请求。它可以帮助安全研究人员在测试漏洞时收集信息,例如SSRF/ XXE/ RCE等)。

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220623110429.png" alt="image-20220623110429395" style="zoom: 80%;" />

当扫描完后,会告诉我们可以使用哪些利用链进行命令执行。

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220623111159.png" alt="image-20220623111159816" style="zoom:80%;" />

使用netcat监控5555端口。

![image-20220623111353203](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220623111353.png)

使用其简便操作进行反弹shell,指定反弹shell的连接地址为192.168.219.1:5555后,进行反弹shell的连接。

<img src="https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220623112315.png" alt="image-20220623112315113" style="zoom: 67%;" />

成功连接。

![image-20220623112147160](https://woniumd.oss-cn-hangzhou.aliyuncs.com/security/zhengyu/20220623112147.png)

#### 2.4 修复建议

1. 更新shiro到1.2.4以上的版本。
1. 不使用默认的加密密钥,改为随机生成密钥。

### 三、参考文章

1. Shiro(一):Shiro介绍及主要流程 (https://www.cnblogs.com/insaneXs/p/10999384.html)

2. Shiro反序列化漏洞详细分析(https://www.anquanke.com/post/id/228889)
3. Shiro反序列化分析带思路及组件检测笔记(https://xz.aliyun.com/t/8997)

相关推荐

  1. Shiro-550序列漏洞

    2024-07-21 23:28:03       20 阅读
  2. shiro序列与fastjson序列漏洞原理

    2024-07-21 23:28:03       74 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-21 23:28:03       106 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-21 23:28:03       116 阅读
  3. 在Django里面运行非项目文件

    2024-07-21 23:28:03       95 阅读
  4. Python语言-面向对象

    2024-07-21 23:28:03       103 阅读

热门阅读

  1. Kotlin单例、数据类、静态

    2024-07-21 23:28:03       29 阅读
  2. CSP-J模拟赛day1

    2024-07-21 23:28:03       29 阅读
  3. Linux下双网卡NAT组网

    2024-07-21 23:28:03       29 阅读
  4. Node的API基础

    2024-07-21 23:28:03       28 阅读
  5. C2W3.LAB.N-grams+Language Model+OOV

    2024-07-21 23:28:03       25 阅读
  6. 力扣题解(一和零)

    2024-07-21 23:28:03       35 阅读
  7. urllib&requests

    2024-07-21 23:28:03       26 阅读
  8. 接到需求后的开发步骤

    2024-07-21 23:28:03       30 阅读
  9. C#WPF九宫格图片背景实例

    2024-07-21 23:28:03       31 阅读
  10. 算法学习4——动态规划

    2024-07-21 23:28:03       28 阅读