漏洞描述
Apache Shiro before 1.7.1, when using Apache Shiro with Spring, a specially crafted HTTP request may cause an authentication bypass.[1]
漏洞条件
-
shiro < 1.7.1
-
路径配置 是类似“/*”的只有一个通配符,而不能是类似“/**”的双统配符
-
没有手动配置CVE-2020-17510修复补丁 [4]
-
使用spring
漏洞复现
环境
基础环境:
- shiro:1.7.0
- springboot:2.7.4
- 没有手动配置CVE-2020-17510修复补丁
shiro配置:
@Bean
ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
bean.setLoginUrl("/login");
bean.setSuccessUrl("/loginSuccess");
bean.setUnauthorizedUrl("/unauthorized");
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
//url --> filter1,filter2....
map.put("/print", "authc, perms[printer:print]");
map.put("/query", "authc, perms[printer:query]");
map.put("/admin/*", "authc, roles[admin]"); // 如果是"/admin/**"则漏洞无效
map.put("/login","authc");
bean.setFilterChainDefinitionMap(map);
return bean;
}
controller:
@GetMapping("/admin/{param}")
public String adminInfo(@PathVariable String param) {
if(param == null){
return "you are admin";
}
return "Admin Info: " + param;
}
测试
payload
/admin/%20
结果:
漏洞分析
请求同上。
漏洞入口:PathMatchingFilterChainResolver.getchain(...)
getPathWithinApplication(request)保留了空格
springweb路径匹配路口:AbstractHandlerMethodMapping.getHandlerInternal(...)
从漏洞复现结果可知,最终能够匹配“/admin/{param}"。
但是为什么shiro中"/admin/ "(末尾有空格)无法匹配"/admin/*"?
PathMatchingFilterChainResolver.pathMatches(String pattern, String path) --不断跟进--->
AntPathMatcher.doMatch(pattern, path, true);
-
第一步:将传入的路径以分割符”/“,分割路径为数组:不过,从图中发现,pattern(配置的路径)能够正常的被分割为["admin","*"],然而path 没有被分割为["admin"," "],而是缺少了空格符。
-
第二步:进入以下while循环,进行循环匹配
// Match all elements up to the first **
while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
String patDir = pattDirs[pattIdxStart];
if ("**".equals(patDir)) {
break;
}
if (!matchStrings(patDir, pathDirs[pathIdxStart])) {
return false;
}
pattIdxStart++;
pathIdxStart++;
}
-
第三步:由于pathDirs长度小于pattDirs长度,所以最终path会先耗尽(exhausted),从而进入下图分支(最上层的if条件),最终返回false
综上可知,最根本的原因就在StringUtils.tokenizeToStringArray(...)
:分割时去除了空格
public static String[] tokenizeToStringArray(String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {
if (str == null) {
return null;
} else {
StringTokenizer st = new StringTokenizer(str, delimiters);
List tokens = new ArrayList();
while(true) {
String token;
do {
if (!st.hasMoreTokens()) {
return toStringArray(tokens);
}
token = st.nextToken();
if (trimTokens) {
//token = " "时,token.trim()会返回去除首尾空格后的字符串:""
//因此最终数组中没有空格符
token = token.trim();
}
} while(ignoreEmptyTokens && token.length() <= 0);
tokens.add(token);
}
}
}
trim(): Returns a string whose value is this string, with any leading and trailing whitespace removed.
漏洞修复
将trimTokens
参数设置为false: [3]
Reference
[1] Security Reports | Apache Shiro
[3] Shiro Commit
[4] Shiro CVE-2020-17510 路径绕过 - FreeBuf网络安全行业门户
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)