Shiro550

shiro550和fastjson作为攻防演练的利器,前面学习了fastjson的相关利用和回显,本篇主要来学习一下shiro550的漏洞原理。

1、漏洞原因

在 Shiro <= 1.2.4 中,AES 加密算法的key是硬编码在源码中,当我们勾选remember me 的时候 shiro 会将我们的 cookie 信息序列化并且加密存储在 Cookie 的 rememberMe字段中,这样在下次请求时会读取 Cookie 中的 rememberMe字段并且进行解密然后反序列化,且AES的key 为固定的。

2、环境搭建及复现

https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4
jdk1.7
Tomcat8
idea

坑点

原有版本的jstl会报错修改为1.2

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 依赖cc链 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

toolchains的错误

<?xml version="1.0" encoding="UTF8"?>
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<version>1.6</version>
<vendor>sun</vendor>
</provides>
<configuration>
<jdkHome>/Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk</jdkHome>
</configuration>
</toolchain>
</toolchains>

然后启动即可

漏洞复现

3、漏洞分析

3.1、生成cookie

3.1.1、原理解析

shiro会提供rememberme功能,可以通过cookie记录登录用户,从而记录登录用户的身份认证信息,即下次无需登录即可访问。而其中对rememberme的cookie做了加密处理,漏洞主要原因是加密的AES密钥是硬编码在文件中的,那么对于AES加密算法我们已知密钥,并且IV为cookie进行base64解码后的前16个字节,因此我们可以构造任意的可控序列化payload。

cookie的处理类org.apache.shiro.web.mgt.CookieRememberMeManager类出现了漏洞,而它继承了AbstractRememberMeManager类。

处理rememberme的cookie的类为org.apache.shiro.web.mgt.CookieRememberMeManager,其中的rememberSerializedIdentity方法,主要就是设置用户的cookie的值,这个值是通过base64解密serialized获取的。

我们继续看看父类

首先定义默认的秘钥通过base64固定解码得到,这个就是我们上门工具爆破出来的秘钥

还有就是方法 onSuccessfulLogin,这方法就是登录成功的意思,判断isRememberMe,该方法就是判断token中是够含rememberMe。所以当我们成功登录时,如果勾选了rememberme选项,那么此时将进入onSuccessfulLogin方法

我们继续往下走,跟进rememberIdentity方法,这三个参数上面有解释我,我的理解是

subject:就是rememberMe字段的主体
token:成功的身份令牌
authcInfo:成功的身份验证信息

然后进入方法体,获取验证身份的主体,继续调用重载方法,再跟进去看看

进入后我看到,把accountPrincipals(身份验证信息)转成了byte字节,然后就是调用我们一开始分析的rememberSerializedIdentity方法设置cookie的值了。

这就是生成cookie的过程,但是还是有些疑惑,convertPrincipalsToBytes是怎么实现的和默认秘钥在哪里使用了,我们在org.apache.shiro.mgt.AbstractRememberMeManager的onSuccessfulLogin方法打下断点看看。

3.1.1、idea调试

首先我们idea调试启动,然后勾选Rememberme,登录。

成功捕获断点,跟进去

跟我们上面分析的一样,我们直接跟进convertPrincipalsToBytes方法

我们先跟进serialize,看他怎么序列化数据的

获取序列化对象继续调用serialize,跟进去

看到这我们就能很清晰的看到他是怎么序列化数据的了。我们继续回到convertPrincipalsToBytes方法

接着判断getCipherService是否为空,字面意思就是获取密码算法服务,我们也跟进去看看

直接返回了加密算法服务,在注解中也可以看到,为CBC模式的AES算法。那他在哪里定义的呢

我们看到在构造方法中,创建了AES加密服务,并且设置了加密服务的key,这个key就是我们上面定义的。

我们继续返回convertPrincipalsToBytes方法中。看到其使用了encrypt方法对序列化后的principals进行加密,我们也跟进去看看。

首先还是获取了加密算法服务(AES),调用该算法的加密方法encrypt,这个算法有两个参数,第一个我们知道就是序列化的字节码,我们看第二个,英文意思是获取加密算法的key,我们继续跟进去

我们看到直接返回了加密key,这个key是通过setEncryptionCipherKey设置的,而setCipherKey调用了setEncryptionCipherKey,也就是我们在encrypt方法中的getCipherService方法设置的.

我们继续回到encrypt方法,参数是 bytes和key继续跟进

判断是够创建初始化载体,我们跟进generateInitializationVector

他会调用父类的generateInitializationVector,继续跟进

我们可以看到,size为128(定义的静态字符串),然后新建长度为16的字节数组,调用了ensureSecureRandom,跟进看看

就是获取一个随机值,nextBytes方法用于生成随机字节并将其置于用户提供的字节数组

然后返回,所以ivBytes就是一个随机的16位字节数组

我们继续回到encrypt,然后调用重载方法,参数为byte数组、key,16为的随机字节数组ivBytes和布尔true。我们继续跟进

encrypt就是我们最终的加密实现算法。把ivbytes和encrypted一起放入output,然后返回

最后通过rememberSerializedIdentity设置cookie值

上面都是序列的过程,那么在那里反序列化呢

3.3、解析cookie

org.apache.shiro.mgt.AbstractRememberMeManager#getRememberedPrincipals的方法中,会从cookie中获取身份信息,我们在此打下断点,然后刷新web页面,成功捕获,会通过org.apache.shiro.web.mgt.CookieRememberMeManager类的getRememberedSerializedIdentity方法获取bytes,我们也跟进去看看

可以看到该类会获取cookie,然后解密base64加密的字段,获取字节数组返回。

我们继续返回其父类org.apache.shiro.mgt.AbstractRememberMeManager#getRememberedPrincipals的方法中,会调用convertBytesToPrincipals方法,跟生成cookie相反,我们也跟进去看看。

重复代码不再一一解释,直接进入decrypt方法

发现跟加密一样,通过decrypt解密AES。然后返回

然后反序列化解密的字符串

最后调用readObject方法,造成反序列化。

值得注意的是该readObejct方法,是shiro重写过的,重写了resolveClass函数,调用了ClassUtils.forName(),而原生的则是Class.forName().所以导致很多链用不了 ,也是为什么要导入cc4的组件了。我们来看看ClassUtils.forName()

看到org.apache.shiro.util.ClassUtils的forName()方法,他是调用了而ClassLoader.loadClass,该方法不支持装载数组类型的class,也就是cc1、cc3等用的Transform数组类都不行了,但是cc2和cc4是可以的 ,其利用的是javassist的TemplateImpl类实现的,所以不影响。

还有就是通过改造利用链实现shiro原生的命令执行,具体查看https://www.anquanke.com/post/id/192619#h2-3。

参考

https://y4er.com/post/shiro-rememberme-rce/

https://www.cnblogs.com/nice0e3/p/14183173.html

https://xz.aliyun.com/t/6493

https://www.anquanke.com/post/id/192619#h2-3

shiro550反序列学习的更多相关文章

  1. JDK7u21反序列链学习

    JDK7u21 1.前置知识 jdk7u21是一条不依赖CommonsCollections库依赖的,看利用链所有知识其实跟CommonsCollections也有重复,我们来学习一下以前没学过的类或 ...

  2. Fastjsonfan反序列链学习前置知识

    Fastjson前置知识 Fastjson 是一个 Java 库,可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符串转换为 Java 对象. Fastjson 可以操作任何 ...

  3. CommonsCollection2反序列链学习

    CommonsCollection2 1.前置知识 CmonnosCollection2需要用到Javassist和PriorityQueue 1.1.Javassist Javassist是一个开源 ...

  4. PHP反序列漏洞学习

    0x00 序列化和反序列化 在PHP中,序列化和反序列化对应的函数分别为serialize()和unserialize(). 序列化:serialize()将对象转换为字符串以便存储传输的一种方式. ...

  5. 通过WebGoat学习java反序列化漏洞

    首发于freebuff. WebGoat-Insecure Deserialization Insecure Deserialization 01 概念 本课程描述了什么是序列化,以及如何操纵它来执行 ...

  6. web渗透学习目录

    一,基础学习 01.基础学习 [[编码总结]] [[JSON三种数据解析方法]] [[js加密,解密]] [[Internet保留地址和非保留地址.内网和公网.VNC和UltraVN]] 代理 [[S ...

  7. WCF学习之旅—WCF第二个示例(五)

    二.WCF服务端应用程序 第一步,创建WCF服务应用程序项目 打开Visual Studio 2015,在菜单上点击文件—>新建—>项目—>WCF服务应用程序.在弹出界面的“名称”对 ...

  8. Redis学习笔记二

    学习Redis添加Object时,由于Redis只能存取字符串String,对于其它数据类型形容:Int,long,double,Date等不提供支持,因而需要设计到对象的序列化和反序列化.java序 ...

  9. Node.JS 学习路线图

    转载自:http://www.admin10000.com/document/4624.html 从零开始nodejs系列文章, 将介绍如何利Javascript做为服务端脚本,通过Nodejs框架w ...

随机推荐

  1. Spring cache源码分析

    Spring cache是一个缓存API层,封装了对多种缓存的通用操作,可以借助注解方便地为程序添加缓存功能. 常见的注解有@Cacheable.@CachePut.@CacheEvict,有没有想过 ...

  2. cookie可设置哪些属性?httponly?

    chrome控制台的application下可查看: cookie name 字段为一个cookie的名称. value 字段为一个cookie的值. domain 字段为可以访问此cookie的域名 ...

  3. GC是什么? 为什么要有GC?   

    GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过 ...

  4. Struts2的Action中获取request对象的几种方式?

    通过ActionContext.getSession获取 通过ServletActionContext.getRequest()获取 通过SessionAware接口注入 通过ServletReque ...

  5. JVM调优常用参数配置

    堆配置 -Xms:初始堆大小 -Xms:最大堆大小 -XX:NewSize=n:设置年轻代大小 -XX:NewRatio=n:设置年轻代和年老代的比值.如:为3表示年轻代和年老代比值为1:3,年轻代占 ...

  6. 学习Apache(五)

     apache目前主要有两种模式:prefork模式和worker模式: 1)prefork模式(默认模式) prefork是Unix平台上的默认(缺省)MPM,使用多个子进程,每个子进程只有一个线程 ...

  7. xacro 语法总结

    xacro是为了解决在编写urdf文件过程中,出现的标签内容重复,但又不得不去写.一些值的计算有依赖的问题.为了和urdf文件区分,我们定义的模型文件名后缀为.xacro. 从功能的角度来说,xacr ...

  8. 5V转10.5V原理图

  9. Mac 安装WordPress

    Mac 安装WordPress 一.环境要求 PHP 5.2.4或更新版本 MySQL 5.0或更新版本 WebServer(可以选择Apache.nginx等支持PHP的,这里我选择Apache) ...

  10. python爬虫---豆瓣Top250电影采集

    代码: import requests from bs4 import BeautifulSoup as bs import time def get_movie(url): headers = { ...