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. 【技术干货】华为云FusionInsight MRS的自研超级调度器Superior Scheduler

    Superior Scheduler是一个专门为Hadoop YARN分布式资源管理系统设计的调度引擎,是针对企业客户融合资源池,多租户的业务诉求而设计的高性能企业级调度器. Superior Sch ...

  2. error LNK2019: 无法解析的外部符号 _WinMain@16,该符号在函数。。。使用

    一,问题描述 MSVCRTD.lib(crtexew.obj) : error LNK2019: 无法解析的外部符号 _WinMain@16,该符号在函数 ___tmainCRTStartup 中被引 ...

  3. java-开发规约

    public class TenTen { /** * 代码中的命名不能用下划线或美元符号开始和结束:例如 _name name_ $name name$ */ /** * 类名必须使用UpperCa ...

  4. 分布式集群中为什么会有 Master?

    在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机 器可以共享这个结果,这样可以大大减少重复计算,提高性能,于是就需要进行 leader 选举.

  5. 如何实现集群中的 session 共享存储?

    Session 是运行在一台服务器上的,所有的访问都会到达我们的唯一服务器上,这 样我们可以根据客户端传来的 sessionID,来获取 session,或在对应 Session 不 存在的情况下(s ...

  6. 什么是 spring?

    Spring 是个 java 企业级应用的开源开发框架.Spring 主要用来开发 Java 应用, 但是有些扩展是针对构建 J2EE 平台的 web 应用.Spring 框架目标是简化 Java 企 ...

  7. 学习Haproxy (八)

    Unix套接字命令(Unix Socket commands) socat是一个多功能的网络工具,名字来由是"Socket CAT",可以看作是netcat的N倍加强版,socat ...

  8. 链接克隆的设置和kvm 安装

    1.重新定义udev规则 删除   /etc/udev/rules.d/70-persistent-net.rules  网卡信息 #   >    /etc/udev/rules.d/70-p ...

  9. Vue报错之"[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead......"

    一.报错截图 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the p ...

  10. iView 一周年了,同时发布了 2.0 正式版,但这只是开始...

    两年前,我开始接触 Vue.js 框架,当时就被它的轻量.组件化和友好的 API 所吸引.之后我将 Vue.js 和 Webpack 技术栈引入我的公司(TalkingData)可视化团队,并经过一年 ...