0x00 背景

文章记录了分析shiro反序列化漏洞的思路和过程,漏洞用的次数挺多,感觉不认真走一遍分析还是缺点什么。排版也是按照我所理解的分析1day的思路进行排版的,emm~ 不太专业哈 见谅 ┭┮﹏┭┮

友情提示:文章写的感觉比较亲民,理论上有一些其他语言的基础都可以阅读,比较倾向于将东西写的详细(废话很多),就是那种看帖按着步骤走跟着思考大概自行理解的程度(记性不好,不写可能会忘的)

0x01 梦开始的地方

一切都要从官方shiro的某个人提出的问题描述开始说起 ~ 下图为谷歌翻译结果

url: https://issues.apache.org/jira/browse/SHIRO-550

通过描述可知:

    1. shiro <= 1.2.4 存在反序列化漏洞
    1. shiro的CookieRememberMeManager类里对漏洞参数rememberMe进行序列化,加密等操作,我理解成这个类和这个漏洞有关系,可以当成入口点
    1. shiro对每次访问都会用到"记住我"的功能进行以下操作:

    2. 检索rememberMe cookie的值 //cookie中是否有这个参数

    3. Base 64解码 //对参数的值进行解码
    4. 使用AES解密 //对参数的值再进行解密
    5. 使用Java序列化(ObjectInputStream)反序列化。 //对解出的参数的值进行反序列化
    1. 源代码存在默认的AES加密密钥,所有能够查看源代码的人都可以知道默认密钥是什么

以此确定一个需要通过Debug代码来达成的大概目的:

  • 通过控制rememberMe参数的值传输加密好的恶意序列化payload,成功让shiro进行解密到反序列化的步骤就可以达到执行命令的目的
      1. 如何控制rememberMe参数的值
      1. 如何对payload进行加密
      1. 根据加密方法对生成恶意序列化payload进行加密构造利用工具

0x02 科普时间

  • AES加密算法:属于对称加密算法,意思就是加密和解密用相同的密钥

    • 加密过程:

      明文 --> AES加密函数 + 密钥位数(128/192.256) + iv(初始化向量) + 密钥(key) + 模式(CBC和GCM等) + padding(填充方式)--> 密文

  • IDEA的Debug按钮功能:

    Step Over : 单步执行,遇到方法直接获得返回值而不会进入
    Step Into : 单步执行,遇到方法会进入方法,不会进入jdk实现的方法中
    Force Step Into : 可以进入任何的方法,比如jdk,jar包
    Step Out : 在方法内会直接获得返回值跳出该方法
    Run To Cursor : 让程序运行到鼠标所在的位置
    Drop Frame : 返回上一步,摧毁当前方法获得的值
    Resume Program : 运行至下一个断点所在位置

0x03 分析独白

1. 环境配置

研究的前提自然是要搭建好环境

下载shiro的漏洞环境,这里使用war包,放在tomcat的webapps里,启动tomcat,然后war包自动解析成文件夹,使用IDEA打开此文件夹

顺便讲一下IDEA配置调试shiro

Run -> Edit Configurations -> 点击+号添加TomcatServer(Local) -> Server中配置Tomcat路径 -> 选择JRE版本 ->Deployment中点击+号添加tomcat里生成的shiro文件夹 -> 点击Apply

运行起来

2. 分析过程

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

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

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

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

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

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

IDEA中按两次shift 搜索咱们前面准备当做入口点的CookieRememberMeManager类,按着函数列表查看后并未发现有关加密的信息,so跟进父类AbstractRememberMeManager去看一下

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

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

点击收藏 | 2 关注 | 1
登录 后跟帖