CVE-2020-1957 Apache Shiro 认证绕过漏洞

漏洞原理分析

Springboot中对使用Apache Shiro进行身份验证、权限控制时,利用Apache Shiro和SpringBoot对URL的处理不同,实现越权访问

比如/xxx/..;/admin/这个路径,在shiro看到“;”分号后,就会进行截断,校验分号前面路径/xxx/..这个路径并没有包含admin/**于是校验通过。Spring Boot看到此路径后,会直接取有效路径/admin/于是就访问成功了

漏洞影响版本:

shiro的1.5.1及之前的版本

漏洞复现

复现环境:vulhub

docker-compose up -d //开启环境 docker-compose ps 查看环境

访问一下

点击Login

用bp抓包,

访问/admin 显示302重定向跳转到登录界面

将url改为/xxx/..;/admin/后绕过了登录

注意这里是 两个点 .. 因为我们进入xxx路径中,然后需要 ../返回原目录

成功,

关闭环境

原理分析

以/xxx/..;/admin/ 为例,一步步分析整个流程中的请求过程

protected String getPathWithinApplication(ServletRequest request) {
    return WebUtils.getPathWithinApplication(WebUtils.toHttp(request));
}
 
public static String getPathWithinApplication(HttpServletRequest request) {
        String contextPath = getContextPath(request);
        String requestUri = getRequestUri(request);
        if (StringUtils.startsWithIgnoreCase(requestUri, contextPath)) {
            // Normal case: URI contains context path.
            String path = requestUri.substring(contextPath.length());
            return (StringUtils.hasText(path) ? path : "/");
        } else {
            // Special case: rather unusual.
            return requestUri;
        }
    }
 
 
public static String getRequestUri(HttpServletRequest request) {
        String uri = (String) request.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE);
        if (uri == null) {
            uri = request.getRequestURI();
        }
        return normalize(decodeAndCleanUriString(request, uri));
    }

INCLUDE_REQUEST_URI_ATTRIBUTE

此时的URL还是我们传入的原始URL:/xxx/..;/admin/接着,程序会进入到decodeAndCleanUriString(),

 decodeAndCleanUriString 以 ; 截断后面的请求,所以此时返回的就是/xxx/.. 然后程序调用normalize() 对decodeAndCleanUriString()处理得到的路径进行标准化处理,都是一些很常见的标准化方法.

private static String normalize(String path, boolean replaceBackSlash) {
 
        if (path == null)
            return null;
 
        // Create a place for the normalized path
        String normalized = path;
 
        if (replaceBackSlash && normalized.indexOf('\\') >= 0)
            normalized = normalized.replace('\\', '/');
 
        if (normalized.equals("/."))
            return "/";
 
        // Add a leading "/" if necessary
        if (!normalized.startsWith("/"))
            normalized = "/" + normalized;
 
        // Resolve occurrences of "//" in the normalized path
        while (true) {
            int index = normalized.indexOf("//");
            if (index < 0)
                break;
            normalized = normalized.substring(0, index) +
                    normalized.substring(index + 1);
        }
 
        // Resolve occurrences of "/./" in the normalized path
        while (true) {
            int index = normalized.indexOf("/./");
            if (index < 0)
                break;
            normalized = normalized.substring(0, index) +
                    normalized.substring(index + 2);
        }
 
        // Resolve occurrences of "/../" in the normalized path
        while (true) {
            int index = normalized.indexOf("/../");
            if (index < 0)
                break;
            if (index == 0)
                return (null);  // Trying to go outside our context
            int index2 = normalized.lastIndexOf('/', index - 1);
            normalized = normalized.substring(0, index2) +
                    normalized.substring(index + 3);
        }
 
        // Return the normalized path that we have completed
        return (normalized);
    } 
    

经过getPathWithinApplication()函数的处理,最终shiro 需要校验的URL 就是 /xxx/... 最终会进入到 org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver 中的 getChain()方法会URL校验.

由于/xxx/.. 截断了 并不会匹配到 /admin/** 所以shiro权限校验就会通过

最终我们的原始请求/xxx/..;/admin/ 就会进入到 springboot中. springboot对于每一个进入的request请求也会有自己的处理方式,找到自己所对应的mapping. 具体的匹配方式是在:org.springframework.web.util.UrlPathHelper 中的 getPathWithinServletMapping(),然后匹配到了/xxx/..;/admin

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值