Shiro550攻击链分析

# 漏洞利用过程

使用 ysoserial 生成存在恶意命令的反序列化 payload。使用 AES 默认秘钥,生成的 payload 进行 AES/CBC/PKCS5Padding 模式加密,将加密后的结果传入到 HTTP 头部 Cookie 字段的 rememberMe 参数,通过 HTTP 协议发起请求。
注:由于 Shiro 重写了 resolveClass 方法,将原生方法中的 forName 方法替换为 loadClass 方法,由于 loadClass 无法加载数组类型的类,因此存在 Transformer [] 类的 CommonCollections gadget 无法成功利用此漏洞,(例如 ysoserial CommonCollections1、CommonCollections3)

# 代码过程分析

传入的 payload 首先被服务器接收,并传送给 Shiro 拦截器处理
shiro-web (org.apache.shiro.web.servlet.OncePerRequestFilter#doFilter 方法作为入口)

shiro-web
org/apache/shiro/web/servlet/OncePerRequestFilter#doFilterInternal 方法
调用 createSubject 方法创建 Subject

shiro-core
在 org.apache.shiro.mgt.DefaultSecurityManager#getRememberedIdentity 方法调用 getRememberedSerializedIdentity 方法获取 rememberMe 认证的序列化数据。

点击 getRememberedIdentity 方法转跳

在此方法中可以获取传入的 HTTP 请求,响应数据,并解析获取 http 请求中的 cookie 字段值 (payload 所在字段)(base64 形式)。

shiro-core
src/main/java/org/apache/shiro/crypto/JcaCipherService#decrypt
并在后续的程序中进行 base64 解码,将解码后的 byte 流存储在 decoded 变量中,作为后续进行 AES 解密的密文。

返回的密文数据流将会在 org.apache.shiro.crypto.JcaCipherService#decrypt 方法中完成 AES 解密操作。

点击 decrypt 函数跟进

获得的 AES 解密后的明文将在 org.apache.shiro.web.mgt.AbstractRememberMeManager#deserialize 方法中反序列化,执行其中的恶意代码。