跳到正文
Crazy0x70 的头像随笔随想

Shiro 反序列化

/ 12 分钟阅读

更新于:

反序列化原理

Apache Shiro 反序列化漏洞的原理主要涉及 Shiro 的 rememberMe 功能。这个功能利用序列化机制来存储和恢复用户的会话信息。然而,攻击者可以利用这一点,通过构造恶意的序列化数据来执行任意代码。

Shiro 的 rememberMe 功能

Shiro 的 rememberMe 功能用于在用户关闭浏览器后仍然记住用户的登录状态。它通过将用户的会话信息序列化后存储在一个名为 rememberMe 的 Cookie 中。当用户再次访问网站时,Shiro 会从这个 Cookie 中读取数据并反序列化,恢复用户会话。

序列化和反序列化

在 Java 中,序列化是将对象转换为字节流的过程,反序列化是将字节流转换回对象的过程。Shiro 在存储 rememberMe 信息时,会将用户的会话对象序列化并存储在 Cookie 中。

漏洞利用的核心

漏洞的核心在于反序列化过程中对输入数据的信任。攻击者可以通过构造恶意的序列化数据,将其放入 rememberMe Cookie 中。当 Shiro 尝试反序列化这个 Cookie 时,恶意数据会触发任意代码执行。

恶意序列化数据的构造

攻击者通常会使用工具(如 ysoserial )来生成包含恶意代码的序列化对象。例如,攻击者可以利用 Java 自带的类(如 CommonsCollections )来构造一个恶意的序列化对象。当这个对象被反序列化时,会执行攻击者指定的代码。

漏洞利用流程

1.生成恶意序列化数据:攻击者使用工具生成一个包含恶意代码的序列化对象。 2.设置 rememberMe Cookie :攻击者将生成的恶意序列化对象进行 Base64 编码,并设置到 rememberMe Cookie 中。 3.发送请求:攻击者发送带有恶意 rememberMe Cookie 的 HTTP 请求到目标服务器。 4.反序列化执行:服务器在处理请求时,Shiro 会从 rememberMe Cookie 中读取数据并尝试反序列化。此时,恶意代码被执行。

示例

假设攻击者使用 ysoserial 工具生成一个恶意的序列化对象: java -jar ysoserial.jar CommonsCollections1 “touch /tmp/pwned” > payload.bin 然后将生成的 payload.bin 文件内容进行Base64编码,并设置到 rememberMe Cookie 中: base64 payload.bin 生成的 Base64 字符串例如为 rO0ABX…,攻击者将其设置到HTTP请求的 rememberMe Cookie 中:

GET / HTTP/1.1
Host: target.com
Cookie: rememberMe=rO0ABX...

当目标服务器接收到这个请求时,Shiro 会尝试反序列化 rememberMe Cookie 中的内容,从而执行恶意代码 touch /tmp/pwned。

反序列化流量特征

请求头特征

在 Shiro 反序列化攻击中,攻击者通常会修改或添加特定的 HTTP 请求头。常见的请求头特征为 rememberMe Cookie ,这是 Shiro 用来存储用户会话信息的 Cookie 。攻击者会将恶意的序列化数据放入这个 Cookie中 。

Cookie: rememberMe=恶意序列化数据

Base64 编码

Shiro 的 rememberMe Cookie 中的数据通常是 Base64 编码的,因此在检测流量时,可以关注 Base64 编码的字符串,特别是那些解码后可能包含序列化数据的部分。

特定的序列化标记

序列化对象通常以特定的序列化标记开头,这些标记可以帮助识别反序列化攻击。例如,Java 序列化对象通常以 0xac ed 00 05 开头。

异常流量特征

监控网络流量中异常的请求大小和频率,尤其是那些包含大量数据或频繁发送的请求,这些可能是攻击者在尝试利用反序列化漏洞。

监控常见的恶意 Payload

攻击者可能会使用现成的工具和 Payload 来进行攻击,比如使用 ysoserial 工具生成的 Payload ,这些 Payload 通常包含特定的类名和方法调用,例如 CommonsCollections、Jdk7u21 等。

日志分析

在服务器日志中查找异常的 rememberMe Cookie 值,以及与反序列化相关的异常堆栈跟踪。例如:

java.io.InvalidClassException: ...
...

特定的命令和脚本执行特征

如果攻击成功,可能会在服务器上看到异常的命令执行或脚本执行痕迹。监控系统日志、执行命令历史记录等,可以发现异常行为。

Shiro550 和 Shiro721 的区别

shiro 框架目前只有两个利用,一个是550,一个是721。 其中550 是最容易利用的,不需要登录就可以利用;721 是需要登录去爆破它的密钥的,所以它的利用条件比较苛刻

shiro-550

shiro 反序列化漏洞利用有两个关键点,首先是在 shiro<1.24 时,AES 加密的密钥 Key 被硬编码在代码里,只要能获取到这个 key 就可以构造恶意数据让 shiro 识别为正常数据。另外就是 shiro 在验证 rememberMe 时使用了 readObject 方法。

readObject 用来执行反序列化后需要执行的代码片段,从而造成恶意命令可以被执行。攻击者构造恶意代码,并且序列化,AES 加密,base64 编码后,作为 cookie 的 rememberMe 字段发送。Shiro 将 rememberMe 进行编码,解密并且反序列化,最终造成反序列化漏洞。

shiro-721

不需要 key,利用 Padding Oracle Attack 构造出 RememberMe 字段后段的值结合合法的 Remember 。

反序列化不出网

Shiro 反序列化漏洞通常需要能够与目标服务器进行网络通信,才能完成漏洞利用。但是在某些情况下,由于服务器所在的网络环境限制,可能无法直接访问服务器上的恶意 Gadget 所需的资源,如 JNDI 注入时的恶意 LDAP 服务器。这种情况下,称之为 Shiro 反序列化不出网 。针对这种情况,需要采取一些特殊的方法来绕过网络限制完成漏洞利用。下面介绍几种常见的 Shiro反序列化不出网 的利用方法。

利用本地的 Gadget

某些 Gadget 并不需要从远程服务器加载恶意类,而是可以直接利用目标服务器本地已有的类来完成漏洞利用。例如:

  • JRE 自带的 Gadget :利用 JRE 中自带的一些危险的类,如 com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl 等,通过反序列化触发这些类的危险方法,实现任意文件写入或命令执行。
  • 第三方库中的 Gadget :如果目标服务器的 classpath 中包含了一些常见的、存在漏洞的第三方库,如 Apache Commons Collections、Groovy 等,可以直接利用这些库中的 Gadget 进行利用。
  • 应用自身的 Gadget :如果目标应用本身包含了一些危险的类,也可以尝试利用这些类构造 Gadget 链。

利用本地的 JNDI 注入

在 JNDI 注入攻击中,我们通常会在远程服务器上托管一个恶意的 LDAP 服务,并在 JNDI 查找时指向这个 LDAP 服务器。但是在不出网的情况下,我们可以在本地搭建一个恶意的 LDAP 服务。

  • 在目标服务器上找到一个可写的目录,在该目录下创建一个恶意的 LDAP 服务器。
  • 在 Gadget 链中,将 JNDI URL 指向这个本地的 LDAP 服务器,如 ldap://localhost:1389/EvilObject。
  • 当 Shiro 反序列化触发 JNDI 查找时,会连接到本地的 LDAP 服务器,加载恶意的 EvilObject 类,完成利用。

分阶段攻击

如果目标环境非常严格,本地无法直接执行命令或写入文件,可以考虑分阶段进行攻击。

  • 在第一阶段,利用 Shiro 反序列化漏洞,通过本地 Gadget 实现一个跳板,如写入一个 WebShell 、反弹一个 Shell 、或启动一个恶意服务等。
  • 在第二阶段,通过这个跳板,再进一步对目标服务器进行渗透和后渗透,直到完全控制目标服务器。
  • 这种方法需要更多的时间和精力,但是可以帮绕过一些严格的网络限制。

配合其他漏洞

如果目标环境存在其他的安全漏洞,如文件上传、SQL 注入、XXE 等,可以先利用这些漏洞在目标服务器上获得一定的控制权限,然后再利用这些权限来辅助 Shiro 反序列化漏洞的利用。

  • 例如,利用文件上传漏洞,上传一个恶意的 LDAP 服务器 Jar 包,再在 Shiro 反序列化时加载这个本地的 Jar 包。
  • 或者利用 SQL 注入漏洞,在数据库中写入恶意的序列化数据,再通过特定的参数触发 Shiro 对数据库中数据的反序列化。