Shiro CVE-2020-17523 路径绕过
主站 分类 漏洞 工具 极客 2025-1-24 07:53:55 Author: www.freebuf.com(查看原文) 阅读量:11 收藏

freeBuf

主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

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

getPathWithinApplication(request)保留了空格

image

image

springweb路径匹配路口:AbstractHandlerMethodMapping.getHandlerInternal(...)

image

从漏洞复现结果可知,最终能够匹配“/admin/{param}"。

但是为什么shiro中"/admin/ "(末尾有空格)无法匹配"/admin/*"?

PathMatchingFilterChainResolver.pathMatches(String pattern, String path) --不断跟进--->
AntPathMatcher.doMatch(pattern, path, true);
  • 第一步:将传入的路径以分割符”/“,分割路径为数组:image不过,从图中发现,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条件),最终返回falseimage

综上可知,最根本的原因就在StringUtils.tokenizeToStringArray(...):分割时去除了空格

image

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]

image

Reference


[1] Security Reports | Apache Shiro

[2] 文章 - Shiro 历史漏洞分析 - 先知社区

[3] Shiro Commit

[4] Shiro CVE-2020-17510 路径绕过 - FreeBuf网络安全行业门户

本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022


文章来源: https://www.freebuf.com/vuls/420772.html
如有侵权请联系:admin#unsafe.sh