Shiro CVE-2020-11989 路径绕过(越权)

2025-01-27 8 0

漏洞描述

Apache Shiro before 1.5.3, when using Apache Shiro with Spring dynamic controllers, a specially crafted request may cause an authentication bypass.[1]

和CVE-2020-1957漏洞原理非常相似,只是这个漏洞是出现在context-path位置。

漏洞条件

  • 需要配置context-path,如/appName

  • shiro < 1.5.3

  • 使用spring

漏洞复现

环境

shiro : 1.5.2				  //使用的还是javax
spring-boot:2.7.4             //3.xx版本 最低java 17且依赖的是jakarta

springboot配置文件:配置context-path

server:
  port: 9090
  servlet:
    context-path: /test

shiro配置

package com.codereview.cve.config;

import java.util.LinkedHashMap;


import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {

    @Bean
    public IniRealm getIniRealm() {
        return new IniRealm("classpath:shiro.ini");
    }


    @Bean
    public SimpleCookie rememberMeCookie(){
        return new SimpleCookie("rememberMe");
    }


    @Bean
    DefaultWebSecurityManager securityManager(IniRealm iniRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm((Realm)iniRealm);
        manager.setRememberMeManager(new CookieRememberMeManager());
        return manager;
    }

	//url配置
    @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/info", "authc, roles[admin]");
        map.put("/login","authc");
        bean.setFilterChainDefinitionMap(map);
        return bean;
    }



}

shiro.ini:

# format: roleName = permission1, permission2, ..., permissionN
#permission分为`域`:printer 和`操作`:print,query
[roles]
user = printer:print
admin = printer:*


# format: username = password, role1, role2, ..., roleN
[users]
user1 = pswd123, user
admin1 = pswd321, admin

controller
假设存在一个打印机:

package com.codereview.cve.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PrinterController {

    @GetMapping("/login")
    public String login() {
        return "This is a login page";

    }

    @GetMapping("/hello")
    public String index() {
        return "Hello World";
    }


    @RequestMapping ("/loginSuccess")
    public String loginSuccess() {
        return "login success!";
    }

    @GetMapping("/print")
    public String print() {
        return "you are printing content...";
    }


    @GetMapping("/query")
    public String query() {
        return "you are querying content...";
    }

	@GetMapping("/admin/info")
    public String adminInfo() {
        return "Admin Info";
    }


    @GetMapping("/unauthorized")
    public String unauthorized() {
        return "you are unauthorized";
    }


}

测试

  1. 正常登入(以用户user1的身份):
    Shiro CVE-2020-11989 路径绕过(越权)插图

  2. 正常访问管理员权限页面(越权):重定向到未授权页面
    Shiro CVE-2020-11989 路径绕过(越权)插图1

  3. 构造恶意路径,再次访问管理员权限页面:成功越权
    Shiro CVE-2020-11989 路径绕过(越权)插图2

漏洞分析

漏洞路口:PathMatchingFilterChainResolver.getChain(...)
Shiro CVE-2020-11989 路径绕过(越权)插图3

源码如下

public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
        FilterChainManager filterChainManager = getFilterChainManager();
        if (!filterChainManager.hasChains()) {
            return null;
        }
		//获取请求路径
        String requestURI = getPathWithinApplication(request);

        //遍历filterChainManager管理的所有过滤链的名字
    	//也就是配置文件中配置的"/print","/query","/print"
        for (String pathPattern : filterChainManager.getChainNames()) {

            //检查是否匹配,如果匹配则返回pathPattern对应的过滤链
            if (pathMatches(pathPattern, requestURI)) {
                if (log.isTraceEnabled()) {
                    log.trace("省略");
                }
                return filterChainManager.proxy(originalChain, pathPattern);
            }
        }

        return null;
    }

进入getPathWithinApplication(request):

  • 正常访问时(/test/admin/info):能够获取到正确的路径Shiro CVE-2020-11989 路径绕过(越权)插图4

  • 但是当路径为/;anyContent/test/admin/info的时候:

  • Shiro CVE-2020-11989 路径绕过(越权)插图5毫无疑问这时放回的requestUri和所配置的路径不匹配,所以绕过了shiro;

为什么会出先上述结果?

  1. 进入getContextPath():

    未normalize前:
    Shiro CVE-2020-11989 路径绕过(越权)插图6
    normalize之后:根据上述内容可知没有发生变化

  2. 进入getRequestUri():
    Shiro CVE-2020-11989 路径绕过(越权)插图7
    request.getServletPath()能够正常获取到相对路径(应用内部路径)
    但是uri的构造 拼接 了带有分号的context-path:

    Shiro CVE-2020-11989 路径绕过(越权)插图8但是以下函数对带有分号的路径处理仍然是去除分号后所有内容(包括分号)
    Shiro CVE-2020-11989 路径绕过(越权)插图9

但是spring web的路径匹配机制却能够匹配到对应的方法:
入口函数org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal

Shiro CVE-2020-11989 路径绕过(越权)插图10

Shiro CVE-2020-11989 路径绕过(越权)插图11

也就是说,spring在获取contextPath时虽然是与shiro是一致的,但是spring是直接拿 相对路径查询,且去除分号的操作也只针对相对路径,而shiro却还要先拼接出完整路径再去除分号,然后最后又截取一下(正常情况)

漏洞修复

直接获取相对路径,然后去除分号;

Shiro CVE-2020-11989 路径绕过(越权)插图12

private static String getServletPath(HttpServletRequest request) {
        String servletPath = (String) request.getAttribute(INCLUDE_SERVLET_PATH_ATTRIBUTE);
        return servletPath != null ? servletPath : valueOrEmpty(request.getServletPath());
    }

request.getServletPath() 本身会像spring一样处理带分号的请求路径,所以在相对路径中放入分号也没用了:(Shiro CVE-2020-1957详细分析 - FreeBuf网络安全行业门户

Shiro CVE-2020-11989 路径绕过(越权)插图13

//一般为空
private static String getPathInfo(HttpServletRequest request) {
        String pathInfo = (String) request.getAttribute(INCLUDE_PATH_INFO_ATTRIBUTE);
        return pathInfo != null ? pathInfo : valueOrEmpty(request.getPathInfo());
    }
//去除逻辑不变,去除分号后面所有内容(包括分号)
private static String removeSemicolon(String uri) {
        int semicolonIndex = uri.indexOf(';');
        return (semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri);
    }

Reference


Security Reports | Apache Shiro

Apache Shiro 身份验证绕过漏洞 复现(CVE-2020-11989) - 渗透测试中心 - 博客园


4A评测 - 免责申明

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

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

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

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

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

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

相关文章

burpsuite最新版实践分享
pwndbg:一款专为安全漏洞分析设计的GDB插件
WordPress SEO Plugin by Squirrly SEO 认证SQL注入漏洞(CVE-2025-22783)
从靶场到实战:双一流高校多个高危漏洞
THN 每周回顾:顶级网络安全威胁、工具与技巧 [1月27日]
DroneXtract:一款针对无人机的网络安全数字取证工具

发布评论