shiro550反序列学习
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://www.anquanke.com/post/id/192619#h2-3
shiro550反序列学习的更多相关文章
- JDK7u21反序列链学习
JDK7u21 1.前置知识 jdk7u21是一条不依赖CommonsCollections库依赖的,看利用链所有知识其实跟CommonsCollections也有重复,我们来学习一下以前没学过的类或 ...
- Fastjsonfan反序列链学习前置知识
Fastjson前置知识 Fastjson 是一个 Java 库,可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符串转换为 Java 对象. Fastjson 可以操作任何 ...
- CommonsCollection2反序列链学习
CommonsCollection2 1.前置知识 CmonnosCollection2需要用到Javassist和PriorityQueue 1.1.Javassist Javassist是一个开源 ...
- PHP反序列漏洞学习
0x00 序列化和反序列化 在PHP中,序列化和反序列化对应的函数分别为serialize()和unserialize(). 序列化:serialize()将对象转换为字符串以便存储传输的一种方式. ...
- 通过WebGoat学习java反序列化漏洞
首发于freebuff. WebGoat-Insecure Deserialization Insecure Deserialization 01 概念 本课程描述了什么是序列化,以及如何操纵它来执行 ...
- web渗透学习目录
一,基础学习 01.基础学习 [[编码总结]] [[JSON三种数据解析方法]] [[js加密,解密]] [[Internet保留地址和非保留地址.内网和公网.VNC和UltraVN]] 代理 [[S ...
- WCF学习之旅—WCF第二个示例(五)
二.WCF服务端应用程序 第一步,创建WCF服务应用程序项目 打开Visual Studio 2015,在菜单上点击文件—>新建—>项目—>WCF服务应用程序.在弹出界面的“名称”对 ...
- Redis学习笔记二
学习Redis添加Object时,由于Redis只能存取字符串String,对于其它数据类型形容:Int,long,double,Date等不提供支持,因而需要设计到对象的序列化和反序列化.java序 ...
- Node.JS 学习路线图
转载自:http://www.admin10000.com/document/4624.html 从零开始nodejs系列文章, 将介绍如何利Javascript做为服务端脚本,通过Nodejs框架w ...
随机推荐
- MM32F0140的复位脚nRST复用成普通GPIO PA10功能
目录: 1.MM32F0020简介 2.MM32F0020的复位脚nRST和PA10的说明 3.MM32F0020的选项字节说明 4.MM32F0020的FLASH_OBR选项字节寄存器说明 5.MM ...
- redis事务及相关命令介绍
redis事务及相关命令介绍 一.概述:和众多其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制.在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事 ...
- Java如何跳出当前的多重嵌套循环?
在Java中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的break 语句,即可跳出外层循环.例如, outer: for(int i=0;i<1 ...
- 设置一段文字的大小为6px?
谷歌最小12px, 其他浏览器可以更小 通过transform: scale实现
- SpringBoot集成ArtemisMQ,设置动态消息类型
SpringBoot项目集成ArtemisMQ,那么想动态的更换消息类型,怎么办呢? 通过设置org.springframework.jms.support.destination.JmsDestin ...
- 解释 MySQL 外连接、内连接与自连接的区别 ?
先说什么是交叉连接: 交叉连接又叫笛卡尔积,它是指不使用任何条件,直接将一 个表的所有记录和另一个表中的所有记录一一匹配. 内连接 则是只有条件的交叉连接,根据某个条件筛选出符合条件的记录,不符合 条 ...
- java模板设计
- 排序 | 冒泡排序的优化与qsort快速排序
冒泡排序 冒泡排序 Bubble_Sort,是极为简单的一种排序算法.虽然效率差一点,但好在具有结构简单,容易理解,易于操作等优点.冒泡排序就是把小的元素往前调或者把大的元素往后调.在相邻的两个元素间 ...
- Numpy使用Matplotlib实现可视化绘图
Numpy使用Matplotlib实现可视化绘图 可以直接将Numpy的数组传给Matplotlib实现可视化绘图: 曲线图 饼图 柱状图 直方图 1. 绘制正弦曲线 2. 绘制饼图 3. 柱状图 4 ...
- 解决使用 swiper 常见的问题
使用 swiper 的过程中个人总结 1. swiper插件使用方法, 直接查看文档 swiper基础演示 swiper API文档 2.swiper近视初始化时, 其父级元素处于隐藏状态(displ ...