Shiro CVE-2021-41303 路径绕过

2025-02-01 16 0

漏洞描述

Apache Shiro before 1.8.0, when using Apache Shiro with Spring Boot, a specially crafted HTTP request may cause an authentication bypass.[1]

漏洞条件

  • shiro <1.8.0
  • 错误的的url配置
    假设说”/admin"目录下有一个特殊页面"/admin/anonPage"不用登入也能访问,但是却错误地配置成以下内容:
map.put("/admin/*", "authc");   //若是"/admin/**" 则漏洞无效
map.put("/admin/anonPage", "anon");  //"anon" 是anonymous的缩写,表示不用登入即刻访问

按照配置而言,"/admin/*"是包含 ”/admin/anonPage“(或"/admin/anonPage/")的,所以按正确逻辑来讲,当请求是”/admin/anonPage"(或“/admin/anonPage/")shiro只能匹配第一项,永远不会匹配第二项,也就是说第二项配置是无效的。

  • shiro是按照配置顺序匹配请求路径
  • 从逻辑来讲,"/admin/anonPage"和"/admin/anonPage/"它们是相同,springweb中的匹配路径规则是如此,shiro的匹配规则会将后者处理成前者后再匹配,最终效果也是两者相同

正确的配置是两个配置交换顺序,优先匹配特例。
但现在配置是错误的,shiro却没有做出对应“正确”的反应,即以上配置可以绕过。

漏洞复现

配置环境

基础:

shiro : 1.7.1
spring : 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");
        map.put("/admin/anonPage", "anon");
        map.put("/login","authc");
        bean.setFilterChainDefinitionMap(map);
        return bean;
    }

controller

@GetMapping("/admin/anonPage")
public String adminInfo() {

    return "This is an anonymous page";
}
  1. url == "/admin/anonPage":
    Shiro CVE-2021-41303 路径绕过插图
    很明显,由于没有会话id,因此此请求是匿名的(anonymous),但是"/admin/*"是"authc",是需要验证(即登入)的,因此重定向到登入页面。
  2. url == "/admin/anonPage/"
    Shiro CVE-2021-41303 路径绕过插图1

漏洞分析

Shiro CVE-2021-41303 路径绕过插图2

首先需要知道,自shiro1.7.1开始,PathMatchingFilterChainResolver.getChain(...)的匹配规则发生了一个比较明显的改变

shiro 1.7.0:

public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
        FilterChainManager filterChainManager = getFilterChainManager();
        if (!filterChainManager.hasChains()) {
            return null;
        }

        String requestURI = getPathWithinApplication(request);

        // in spring web, the requestURI "/resource/menus" ---- "resource/menus/" bose can access the resource
        // but the pathPattern match "/resource/menus" can not match "resource/menus/"
        // user can use requestURI + "/" to simply bypassed chain filter, to bypassed shiro protect
        if(requestURI != null && !DEFAULT_PATH_SEPARATOR.equals(requestURI)
                && requestURI.endsWith(DEFAULT_PATH_SEPARATOR)) {
            requestURI = requestURI.substring(0, requestURI.length() - 1);
        }


        //the 'chain names' in this implementation are actually path patterns defined by the user.  We just use them
        //as the chain name for the FilterChainManager's requirements
        for (String pathPattern : filterChainManager.getChainNames()) {
            if (pathPattern != null && !DEFAULT_PATH_SEPARATOR.equals(pathPattern)
                    && pathPattern.endsWith(DEFAULT_PATH_SEPARATOR)) {
                pathPattern = pathPattern.substring(0, pathPattern.length() - 1);
            }

            // If the path does match, then pass on to the subclass implementation for specific checks:
            if (pathMatches(pathPattern, requestURI)) {
                if (log.isTraceEnabled()) {
                    log.trace("省略");
                }
                return filterChainManager.proxy(originalChain, pathPattern);
            }
        }

        return null;
    }

shiro 1.7.1:

public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
    FilterChainManager filterChainManager = getFilterChainManager();
    if (!filterChainManager.hasChains()) {
        return null;
    }

    final String requestURI = getPathWithinApplication(request);
    final String requestURINoTrailingSlash = removeTrailingSlash(requestURI);

    //the 'chain names' in this implementation are actually path patterns defined by the user.  We just use them
    //as the chain name for the FilterChainManager's requirements
    for (String pathPattern : filterChainManager.getChainNames()) {
        // If the path does match, then pass on to the subclass implementation for specific checks:
        if (pathMatches(pathPattern, requestURI)) {
            if (log.isTraceEnabled()) {
                log.trace("....");
            }
            return filterChainManager.proxy(originalChain, pathPattern);
        } else {

            // in spring web, the requestURI "/resource/menus" ---- "resource/menus/" bose can access the resource
            // but the pathPattern match "/resource/menus" can not match "resource/menus/"
            // user can use requestURI + "/" to simply bypassed chain filter, to bypassed shiro protect

            pathPattern = removeTrailingSlash(pathPattern);

            if (pathMatches(pathPattern, requestURINoTrailingSlash)) {
                if (log.isTraceEnabled()) {
                    log.trace("....");
                }

                //漏洞所在!!!
                return filterChainManager.proxy(originalChain, requestURINoTrailingSlash);
            }
        }
    }

    return null;
}

前者是直接去除请求url和pattern末尾的slash(“/”),然后进行匹配;后者是先不去除slash匹配一次,若不匹配则去除slash后再匹配一次。

Shiro CVE-2021-41303 路径绕过插图3

shiro虽然"/admin/anonPage/"没有直接匹配到 "/admin/*",但是在第二个分支,将其尾部slash去除后,是匹配上了的。那为什么明明匹配上了 "/admin/*",却还是被绕过了?

原因在于断点处(第二个分支):

filterChainManager.proxy(originalChain, requestURINoTrailingSlash);

可以看到,第二个参数,也就是要选择的chainName是去除尾部slash后的requestURINoTrailingSlash(即“/admin/anonPage”)

public FilterChain proxy(FilterChain original, String chainName) {
        NamedFilterList configured = getChain(chainName);   //底层调用Map
        if (configured == null) {
            String msg = "There is no configured chain under the name/key [" + chainName + "].";
            throw new IllegalArgumentException(msg);
        }
        return configured.proxy(original);
    }

所以在获的过滤链时获取的自然就是“/admin/anonPage”对应的过滤链(anon)

漏洞修复

其实从漏洞分析部分可知,这个漏洞本质上是一个bug。[3]

其修复逻辑如下:[2]

Shiro CVE-2021-41303 路径绕过插图4

将传递的参数改为pathPattern

总结

本次漏洞比较特殊,是“在错误配置下,没有执行对应”正确“行为”类型的漏洞,算是收获了漏洞理解的一种角度。

Reference


[1] Security Reports | Apache Shiro

[2] Backport SHIRO-825 · apache/shiro@4a20bf0

[3] [SHIRO-825] Trailing slash in URI results in "IllegalArgumentException: There is no configured chain under the name/key" - ASF JIRA

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


4A评测 - 免责申明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。

不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。

本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!

程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。

侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)

相关文章

KrbRelayEx:一款针对Kerberos的网络请求中继与转发工具
Hayabusa:一款针对Windows事件日志的威胁搜索与取证分析工具
Shiro CVE-2022-40664 请求转发导致的验证绕过
Shiro CVE-2023-22602 补丁失效导致的路径匹配绕过
谷歌修复安卓内核零日漏洞,攻击者已利用该漏洞发起攻击
Shiro CVE-2023-34478 路径规范化不一致

发布评论