前言
2020年12月25日下午,我们公司网站站点被关闭并告知存在Apache shiro Java 反序列化漏洞的情况,这次应该是教育局联合公安部门一起的一次护网行动,我们公司因为主要是做教育行业相关的业务,当然也在监管其中。很幸运~我们被查到了。
那我今天就好好聊聊这一块儿的问题,和我遇到的所见所闻~当然~如果各位看官觉得有什么问题~也能给予见解。
25日下午网站关闭收到通知,我就赶紧在看这一块的问题和解决办法。所幸没有什么太大的技术难度
报告编号:B6-2021-020302
报告来源:360CERT
1、风险等级评判
360CERT对该漏洞的评定结果如下:
威胁等级:中危
影响面积:广泛
360CERT评分:7.0
2、漏洞简述
360CERT监测发现 Apache Shiro
发布了 Apache Shiro 验证绕过漏洞
的风险通告,该漏洞编号为 CVE-2020-17523
,漏洞等级:中危
,漏洞评分:7.0
。
当 Apache Shiro
与 Spring 框架
结合使用时,在一定权限匹配规则下,攻击者可通过 构造特殊的 HTTP 请求包绕过身份认证。
对此,360CERT建议广大用户及时将 Apache Shiro
升级到最新版本。与此同时,请做好资产自查以及预防工作,以免遭受黑客攻击。
3、漏洞详情
CVE-2020-17523: 验证绕过漏洞
当 Apache Shiro 低于1.7.1 版本的 Apache Shiro
在与 Spring 框架
结合使用时,在一定权限匹配规则下,攻击者可以通过构造特定的HTTP请求包绕过身份认证,从而访问未授权资源。
漏洞修复分析及方案
反序列化漏洞成因:
rememberMe 功能的 AES 密钥硬编码在代码中,造成密钥泄露。使得恶意攻击者可以利用系统在用户登录并勾选了“记住我”时所生成 cookie 的流程,构造恶意 cookie,服务器收到该 cookie 后解析出的命令可能会造成信息泄露等安全风险。
针对此,我提出三种修复方案。
升级Shiro依赖版本并随机生成密钥
通用修补建议:涉及到 Apache Shiro
应当都升级到1.7.1,在项目中新建随机生成 AES 加解密密钥的方法,在 Shiro 配置文件的 rememberMeManager 中调用该方法进行密钥动态生成。此方案与升级Shiro版本的本质策略相同。
此方案适用于项目后期漏洞修复,可最小化对原有项目的影响。
修复步骤
Step1:
升级所有关于 Shiro 相关的jar包,包含但不限于如下 jar 包:
shiro-cache-1.6.0.jar
shiro-config-core-1.6.0.jar
shiro-core-1.6.0.jar
shiro-ehcache-1.6.0.jar
shiro-lang-1.6.0.jar
shiro-web-1.6.0.jar
Step2:
创建密钥随机生成类GenerateCipherKey。
public class GenerateCipherKey {
public static byte[] getCipherKey() {
KeyGenerator kg;
try {
kg = KeyGenerator.getInstance("AES");
} catch (NoSuchAlgorithmException e) {
String msg="shiro 密钥随机生成异常";
throw new IllegalStateException(msg ,e);
}
kg.init(128);
SecretKey sk = kg.generateKey();
byte[] cipherKey = sk.getEncoded();
return cipherKey;
}
}
此方法与 Shiro1.2.5 或以上版本随机生成秘钥所调用的
org.apache.shiro.crypto.AbstractSymmetricCipherService#generateNewKey() 方法作用一致。
Step3:
修改 shiro-context.xml 文件
修改前:
<!-- rememberMe管理器 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
<property name="cookie" ref="rememberMeCookie"/>
</bean>
修改后:
<!-- rememberMe管理器 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cipherKey" value="#{T(com.cbdata.eduadmin.core.security.GenerateCipherKey).getCipherKey()}"/>
<property name="cookie" ref="rememberMeCookie"/>
</bean>
以上就是所有内容,可以采用此方法进行AES密钥保护,在Shiro配置文件中设置的“随机生成密钥” 已生效,Cookie的加密密钥也变更,不再是Shiro1.2.4 中所采用的默认密钥;
最后~再提一些其他的。
漏洞测试
这里我就提供一下一个扫描工具
https://github.com/feihong-cs/ShiroExploit-Deprecated/releases
下载第一个,如果用浏览器下载可能会有点慢,建议使用迅雷,下载完成后,根目录里面有生成的 jar 包,直接双击打开 ShiroExploit.jar 包即可使用。
其他加密方式
就是在 GenerateCipherKey 类的加密方式上,我不建议大家都用一样的,所以在这里提供了其他的加密方式;
可以参考一下下面的代码
package com.ryx.frame.security.aes;
import java.security.SecureRandom;
import java.util.Date;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import org.apache.commons.codec.binary.Base64;
public class KeyGeneral{
/**
* AES 128,256
* DEA 56
*/
//===========================加密方式======================\\
private static final String ALGORITHM_HMACMD5="HmacMD5";
private static final String ALGORITHM_AES="AES";
private static final String ALGORITHM_DES="DES";
//===========================加密类型与算法无关======================\\
//默认
public static String initDefault() {
String key = "";
try {
KeyGenerator generator = KeyGenerator.getInstance(ALGORITHM_HMACMD5);
SecretKey secretKey=generator.generateKey();
byte[]bytes=encode(secretKey.getEncoded());
key=new String(bytes);
} catch (Exception e) { e.printStackTrace(); }
return key;
}
//安全随机种子
public static String initAESKey(int keysize,long seed) {
String key = "";
try {
KeyGenerator generator = KeyGenerator.getInstance(ALGORITHM_AES);
SecureRandom random=new SecureRandom();
random.setSeed(seed);
generator.init(keysize, random);
SecretKey secretKey=generator.generateKey();
byte[]bytes=encode(secretKey.getEncoded());
key=new String(bytes);
} catch (Exception e) { e.printStackTrace(); }
return key;
}
//安全随机种子
public static String initDESKey(int keysize,long seed) {
String key = "";
try {
KeyGenerator generator = KeyGenerator.getInstance(ALGORITHM_DES);
SecureRandom random=new SecureRandom();
random.setSeed(seed);
generator.init(keysize, random);
SecretKey secretKey=generator.generateKey();
byte[]bytes=encode(secretKey.getEncoded());
key=new String(bytes);
} catch (Exception e) { e.printStackTrace(); }
return key;
}
//===========================base64======================\\
public static byte[] encode(byte[]plainBytes){
Base64 base64=new Base64();
return base64.encode(plainBytes);
}
public static byte[] decode(byte[]cipherText){
Base64 base64=new Base64();
return base64.decode(cipherText);
}
//============================test========================\\
public static void main(String[] args) {
System.out.println("加载默认配置算法为HmacMD5__:"+initDefault());
System.out.println("加载默认配置算法为AES__:"+initAESKey(256,new Date().getTime()));
System.out.println("加载默认配置算法为DES__:"+initDESKey(56,new Date().getTime()));
}
//=====================运行结果
//加载默认配置算法为HmacMD5__:1MeVXQZkMWHPy0VLgpwrO44AIfFq2Y+D6gDqPz7BSLQ3iaZOR18DBI5yaSYtCTEXRQYQpwYV5d1UWVefd6v58A==
//加载默认配置算法为AES__:5pUQCt/CLNK44vL+Nm7mgC7IcX1QfGnVc5BwqOrvk7M=
//加载默认配置算法为DES__:FnldAm04/dY=
}
参考链接
特制报告下载链接
一直以来,360CERT 对全球重要网络安全事件进行快速通报、应急响应。为更好地为政企用户提供最新漏洞以及信息安全事件的安全通告服务,现 360CERT 正式推出安全通告特制版报告,以便用户做资料留存、传阅研究与查询验证。用户可直接通过以下链接进行特制报告的下载。
CVE-2020-17523:Apache Shiro身份认证绕过漏洞通告(PDF)
参上~
注:2021/09/27补博
本人源发布地址: