freeBuf
主站

分类

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

特色

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

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

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

FreeBuf+小程序

FreeBuf+小程序

Shiro CVE-2020-17523 路径匹配绕过
2025-01-28 12:35:32
所属地 广东省

漏洞描述

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

  • 路径配置 是类似“/*”的只有一个通配符,而不能是类似“/**”的双统配符

  • 使用spring

漏洞复现

环境

基础环境:

- shiro:1.7.0
- springboot:2.7.4

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("/admin/*", "authc, roles[admin]");   //   如果是"/admin/**"则漏洞无效
        map.put("/login","authc");
        bean.setFilterChainDefinitionMap(map);
        return bean;
    }

controller:

@ResponseBody
@GetMapping("/admin/{param}")
public String adminInfo(@PathVariable String param) {
    if(param == null){
        return "you are admin";
    }
    return "admin Info: " + param;
}

测试

payload

/admin/%20

结果:
image.png

漏洞分析

请求同上。

漏洞入口: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"," "],而是缺少了空格符。

也就是说相当于把“/admin/ " 变成了“/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 历史漏洞分析 - 先知社区

# 漏洞分析 # Shiro # Java代码审计 # 开源组件安全
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录