ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

shiro550反序列学习

2022-04-27 02:31:43  阅读:139  来源: 互联网

标签:学习 apache shiro550 cookie 序列 序列化 方法 我们 shiro


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

image-20220421195258234

坑点

原有版本的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>

image-20220421195435370

然后启动即可

image-20220421195712873

漏洞复现

image-20220421203614317

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类。

image-20220426230340573

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

image-20220427000507263

我们继续看看父类

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

image-20220426230830597

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

image-20220426231549007

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

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

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

image-20220426233426758

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

image-20220426234224799

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

3.1.1、idea调试

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

image-20220427003515798

成功捕获断点,跟进去

image-20220427003842893

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

image-20220427003909890

image-20220427003940621

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

image-20220427004019394

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

image-20220427004121665

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

image-20220427004247818

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

image-20220427004348174

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

image-20220427004535893

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

image-20220427004716112

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

image-20220427005003365

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

image-20220427005209855

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

image-20220427005518532

image-20220427005647226

image-20220427005727405

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

image-20220427010103797

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

image-20220427010356236

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

image-20220427010634344

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

image-20220427011832217

image-20220427011133512

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

image-20220427011307560

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

image-20220427011801912

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

image-20220427012111715

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

image-20220427012422800

最后通过rememberSerializedIdentity设置cookie值

image-20220427012737973

image-20220427012856831

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

3.3、解析cookie

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

image-20220427014215067

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

image-20220427014456605

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

image-20220427014715380

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

image-20220427014815115

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

image-20220427014906425

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

image-20220427015048159

image-20220427015119267

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

image-20220427015211210

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

image-20220427015359185

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

image-20220427015816256

还有就是通过改造利用链实现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

标签:学习,apache,shiro550,cookie,序列,序列化,方法,我们,shiro
来源: https://www.cnblogs.com/akka1/p/16197406.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有