参考:

Shiro反序列化漏洞-shiro550流程分析

详细shiro漏洞复现过程

Shiroの起始篇

Shiro反序列化分析带思路及组件检测笔记

Shiro/SHIRO-550

编码工具RUNTIME.EXEC

shiro550反序列化漏洞

shiro-550-环境

0x01前言

因为在复现漏洞时,一直都是docker起的环境,对这些java开发的项目的具体内容不是很了解,且不懂这些项目的构建过程,故在此总结一下自己在网上看到的搭建环境的过程。对shiro的介绍很多,上面的文章也有,这里就不缀述了

0x2 环境搭建 git

这是在视频中学到的,直接从github上clone代码到本地,然后git checkout切换版本,还是第一次用这个功能,有点迟了。。。附上介绍链接,git也该再去学习一下,只会个clone是不行的。

git clone https://github.com/apache/shiro.git
cd shiro
git checkout shiro-root-1.2.4

image-20240811191753290

编辑shiro/samples/web目录下的pom.xml,手动添加3.2.1的CC依赖包

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>

image-20240811223850102

然后用IDEA打开项目,eclipse没试过,可以自己去找找教程

image-20240811193059119

然后它会自动下载相关依赖项,这种git下来的项目,右下角也可以看其它远程分支。如果下载有问题,记得去maven配置改一下仓库地址,配置tomcat

image-20240811210245817

选择web的war包部署

image-20240811210311812

成功启动

image-20240811210443461

访问服务

image-20240811210352506

0x03 分析过程

首先第一个目的是控制rememberMe参数的值,先找到参数所在位置,对环境的功能先正常使用一遍

当我访问http://localhost:8080/shiro_web_1_2_4_war/login.jsp 登录时勾选Remember Me后,cookie中出现rememberMe参数,而shiro每次都会对cookie中的rememberMe来进行解密后反序列化操作来确定访问者权限,所以直接在cookie传输rememberMe参数就可以控制shiro反序列化的值

image-20240811211148261

cookie内容比较长,一般就是带有信息的,然后https://cloud.tencent.com/developer/article/1472310这篇文章说jdk要求要1.6,我这里用的是1.8我先用工具试试能不能打

image-20240811211919843

检测得到框架

image-20240811212016403

也是能执行命令的,那1.8应该是没什么问题,好了,我知道为什么不行了,shiro中有个这个依赖问题

image-20240812100218830

这个依赖的1.4版本是不支持jdk1.8的,需要改成1.6,不懂后面没调试成功是不是因为这个原因,试一下切换1.6版本的jdk

image-20240812101934708

注释里也提醒了不要切换版本,但后面又要求要1.7以上的maven3.3+,还是断点没打好

第二个目的是获得加密解密的方法,以此来自行加密解密恶意payload进行传输

如果是导入war包的形式

反编译此漏洞环境中的shiro组件jar包

选中shiro-core-1.2.4.jar -> 右键 -> Add as Library -> ok
选中shiro-web-1.2.4.jar -> 右键 -> Add as Library -> ok

而这里我们直接可以看core和web文件下的代码即可

IDEA中按两次shift 搜索咱们前面准备当做入口点的类,按着函数列表查看后并未发现有关加密的信息,但也有一些关键参数的信息,但我们要找加密函数,so跟进父类AbstractRememberMeManager去看一下(按2下shift,直接搜索)

image-20240811212313713

进入此类可以发现一个很明显的key,根据参数名DEFAULT_CIPHER_KEY_BYTES也可以断定是AES加密中所使用的密钥,同时确实是直接写入了代码中,符合上面通过描述可知的AES密钥硬编码在源代码中的条件

然后发现,我这里左边没有同步打开的文件,方法

image-20240811213045261

如果只有类文件,不能看到里面的成员方法,需要在设置中调整

image-20240811213156692

这样就能显示成员方法了,下面我是根据文章教程设置的断点。

这里我在AbstractRememberMeManager类函数名为encrypt(加密)中下了断点,然后在web端进行登录操作,开始debug,运行至encrypt函数传入参数serialized,然后点击Drop Frame返回上个方法发现传入的serialized的值是我刚才web端登录的用户名root序列化后的数据,根据运行步骤函数名猜测流程是shiro验证完了登录的账号密码,然后根据用户名生成序列化数据准备进行加密了

image-20240811213249566

  1. 设置断点

image-20240811213522860

  1. debug

image-20240811213629346

这里不懂怎么不行,我中途换了个教程https://www.cnblogs.com/h0cksr/p/16189761.html,里面有断点踩坑记录,这个更详细一点,里面docker的环境

如果我们想要断点调试需要在本地文件打断点, 但是我们直接搜索Shiro的cookie管理类文件CookieRememberMeManager的时候会发现有两个选择, 一个是本地的项目文件, 还有一个是Maven通过pom.xml加载的文件但是注意这个文件后面还带了一个Test, 类名为CookieRememberMeManagerTest而不是CookieRememberMeManager

image-20240811224246256

如果我们想要打断点调试的话我们最好在本地文件打断点, 否则可能会失效,但我就是不会停不懂为什么。难道还是要用war包。。。

调试是为了找到加密流程,所以我们这里通过代码直接来推加密流程,因为是对cookie的加密,所以我们就直接继续在这个文件里找加密相关的方法。

image-20240812131532257

序列化,所以我么你可以看看这个,获取Remember序列化的相关方法

image-20240812131903290

然后找到了一个判断填充方式是否是base64的,说明加密流程有base64编码,但我们没发现其它加密方法,所以我们可以去父类看看

image-20240812132020461

这里我们就能明显看到加密解密的相关词语了,查看下具体方法

image-20240812132301109

根据分析,我们知道cipherService里还有一个加密方法,然后需要两个参数,一个序列化后的穿,和一个加密的密钥,我们跟进分析

image-20240812132700467

image-20240812133146725

这里可以找到remember的身份认证的相关方法,就是两步一个解密,一个反序列化,下面先分析反序列化,再分析加密,跟进反序列化的方法

image-20240812133418943

这边调用的是原生的方法,所以可以考虑CC和CB相关的东西,然后分析需要的密钥是什么,直接shift,搜索参数名

image-20240812133618798

发现是一个常量,看一下成员的声明是在哪,往上寻找,发现默认的key值

private static final byte[] DEFAULT_CIPHER_KEY_BYTES = Base64.decode("kPH+bIxk5D2deZiIxcaaaA==");

继续分析,可以发现JcaCipherService类

image-20240812141529612

所以利用就是我们需要构造一个序列化payload然后通过这个密钥去加密,传给服务端,然后服务端解密,反序列化后就会执行我们的payload,然后他这里也有自带的CC和CB,也都是存在漏洞的版本,但CC好像不行用,我们用Maven Helper来看看依赖环境

image-20240812135039243

然后这里可以看到有些依赖是test,有些是compile,只有compile和runtime的才会被用,这里主要是验证,后面听不懂了。。。

补充:

问题解决

1、git开代理还是慢,且容易报error

这里直接把git的代理改成对应cfw的代理即可,一般是7890,然后记得http和https都改一下参考

git config --global --list
git config --global http.proxy s"代理地址"
git config --global https.proxy "代理地址"

image-20240811191452718

gitcheckout:https://blog.csdn.net/raoxiaoya/article/details/111321583

2、mvn编译错误

image-20240812093534602

修改为自己的jdk版本,然后再修改maven的conf文件里的toolchain

image-20240812093824131

记得别在注释里改,一直没用。。。这里用不了1.8,我们换一个1.6的

知识扩展

在视频的链接中,我听到老师说,CC和CB

CC是指CommonsCollections

CB是指commons-beanutils

这两个都是java反序列化漏洞中常用的依赖,我们经常说的CC链和CB链就是这两个东西的利用

https://www.freebuf.com/articles/web/377910.html

https://blog.csdn.net/2301_79724395/article/details/138115837

后面可以补充下这两个的学习