shiro放行静态文件_Shiro权限绕过漏洞分析(CVE20202957)

本文详细分析了Apache Shiro中CVE-2020-2957权限绕过漏洞,探讨了漏洞原因、复现过程、1.5.0及1.5.1版本的绕过方法,以及1.5.2版本的修复措施。建议使用1.5.2及以上版本并谨慎使用通配符路径表达式。
摘要由CSDN通过智能技术生成

前言

2020年3月23号,Shiro开发者Brian Demers在用户社区发表帖子,提醒shiro用户进行安全更新,本次更新进行了三个修复,其中就包括了对编号为CVE-2020-2957的Shrio授权绕过漏洞的修复。漏洞影响shiro 1.5.2版本以下。

8271afd2e6c7b06fe5c242368f058445.png

分析过程

SHIRO-682

根据Shiro开发者在1.5.2版本中提交的commit中关于PathMatchingFilter类的测试用例,可以直接关联到JIRA issueSHIRO-682,该issue在1.5.0版本中进行了修复。而1.5.2版本中更新则是对其绕过的修复。

e9e7b77f15948151a2603ba02b8610f1.png

SHIRO-682的修复了spring框架下uri = uri + ‘/’ 绕过Shiro防护的问题。然后下面的描述则清晰得描述了造成改错误的原因。

在Spring web项目中,请求URI/resource/menus和/resource/menus/都可以访问到服务器的资源。

但在Shiro中的URL路径表达式pathPattern可以正确匹配/resource/menus,但不能正确匹配/resource/menus/,导致过滤链无法正确匹配,从而绕Shiro的防护机制。

556eed0cda3c6c34f7e39921a05be61b.png

Shiro拦截器

Shiro框架通过拦截器功能来实现对用户访问权限的控制和拦截。Shiro中常见的拦截器有anon,authc等拦截器。

1.anon为匿名拦截器,不需要登录就能访问,一般用于静态资源,或者移动端接口

2.authc为登录拦截器,需要登录认证才能访问的资源。

用户可以在Shiro.ini编写匹配URL配置,将会拦截匹配的URL,并执行响应的拦截器。从而实现对URL的访问控制,URL路径表达式通常为ANT格式。如下配置,访问 /index.html主页的时候,Shiro将不会对其进行登录判断,anon拦截器不需要登录就能进行访问。而对于/user/xiaoming 等 /user/xiaogang等接口,authc拦截器将会对其进行登录判断,有登录认证才能访问资源。

[urls]/index.html = anon/user/** = authc

Shiro的URL路径表达式为Ant 格式,路径通配符支持?***。

?:匹配一个字符*:匹配零个或多个字符串**:匹配路径中的零个或多个路径

其中表示匹配零个或多个字符串,/可以匹配/hello,但匹配不到/hello/因为通配符无法匹配路径。假设/hello接口设置了authc拦截器,访问/hello将会被进行权限判断,如果请求的URI为/hello/呢,/URL路径表达式将无法正确匹配,放行。然后进入到spring(Servlet)拦截器,spring中/hello形式和/hello/形式的URL访问的资源是一样的。

漏洞复现

明白上文的内容,漏洞复现就很容易了,复现环境代码主要参考网上的开源demo。

1.下载demo代码shiro-basic。

2.导入idea

3.Shiro版本1.4.2

    <dependency>        <groupId>org.apache.shirogroupId>        <artifactId>shiro-webartifactId>        <version>1.4.2version>    dependency>    <dependency>        <groupId>org.apache.shirogroupId>        <artifactId>shiro-springartifactId>        <version>1.4.2version>    dependency>

4.修改ShiroConfig配置文件,添加authc拦截器的拦截正则

    @Bean    ShiroFilterFactoryBean shiroFilterFactoryBean() {        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();        ...        ...        //map.put("/*", "authc");        map.put("/hello/*", "authc");        bean.setFilterChainDefinitionMap(map);        return bean;    }

5.修改路由控制器方法

@GetMapping("/hello/{currentPage}")    public String hello(@PathVariable Integer currentPage) {        return "hello";}

6.启动应用

访问/hello/1接口,可以看到被authc拦截器拦截了,将会跳转到登录接口进行登录。

34dcfbcc3cd78a25571e6aade96e7ceb.png

访问/hello/1/,成功绕过authc拦截器,获取到了资源。

b956c9a7cb2626d9e51ced90390d0574.png

漏洞成因

漏洞初始成因可以定位到 PathMatchingFilterChainResolver的getChain函数下,该函数作用根据URL路径匹配中配置的url路径表达式来匹配输入的URL,判断是否匹配拦截器,匹配成功将会返回响应的拦截器执行链,让ShiroFither执行权限操作的。

其对于URL路径表达式和输入URL的匹配主要通过pathMathches函数进行匹配。

231616a12cbc91be3b7f9b39edc4316e.png

pathMatches函数其最终会调用shiro.util.AntPathMatcher类中doMatch的对于ant格式的pathPattern和requestURI进行匹配。

//pathMatches:135, PathMatchingFilterChainResolver (org.apache.shiro.web.filter.mgt)protected boolean pathMatches(String pattern, String path) {        PatternMatcher pathMatcher = this.getPathMatcher();        return pathMatcher.matches(pattern, path);}

doMatch:109, AntPathMatcher (org.apache.shiro.util),当Shiro 的Ant格式的pathPattern 中的的通配符是不支持匹配路径的,所以/hello/不能成功匹配/hello/1/,也就不会触发authc拦截器进行权限拦截。从而成功绕过了Shiro拦截器,而后再进入到spring拦截器中,/hello/1/与/hello/1能获取到相同的资源。

1e196c749365da10547bbea55930d34c.png

漏洞修复

该漏洞是由中国开发者在2019年3月25日在ShiroGitHub项目上提交的issue,并PR了分支代码589f10添加漏洞修复代码,最终分支代码在1.5.0版本进行了合并,合并时间为2019年11月20日。

1.5.0版本修复

1.5.0版本修复源自tomsun28提交的PR代码,代码修复位置为pathsMatch:125, PathMatchingFilter (org.apache.shiro.web.filter),该修复方式是通过判断requestURI是否以/为结尾,如果以/结尾的话,则去掉尾部的/符号在与URL表达式进行比较。

也就是当requestURI为/hello/1/等以/为结尾的URI的时候,都会被清除最后的/号,再进行URL路径匹配。

fae57e4eaf738ce24feae4b4bf6f5c91.png

≤1.5.1版本绕过

观察1.5.2版本中新添加的测试用例。

e2652848db84751f26507fbbd69d6b30.png

切换测试版本到1.5.1中,然后从中上面的测试用例提取payload进行绕过。

在1.5.1版本中,添加/还是会直接跳转到登录。

ca27f983653c7fee1e3e50e980b3fbd9.png

绕过payload,/fdsf;/../hello/1,成功绕过。

ef1df0bab4b8f39c202502f4f720a499.png

问题同样可以定位到getChain函数中对于requestURI的获取中,如下图所示,this.getPathWithinApplication(request)获取的requestURI为/fdsf,而不是我们输入的/fdsf;/../hello/1,从而导致后面的URI路径模式匹配返回False,从而再次绕过了shiro拦截器。

0193da3d8c2991ef0244ac66c5337ddc.png

getPathWithinApplication函数中会调用WebUtils (org.apache.shiro.web.util)中的getRequestUri函数获取RequestUri。

public static String getRequestUri(HttpServletRequest request) {        String uri = (String)request.getAttribute("javax.servlet.include.request_uri");        if (uri == null) {            uri = request.getRequestURI();        }        return normalize(decodeAndCleanUriString(request, uri));    }

RequestUri函数中最终调用decodeAndCleanUriString函数对URI进行清洗。

private static String decodeAndCleanUriString(HttpServletRequest request, String uri) {      uri = decodeRequestString(request, uri);      int semicolonIndex = uri.indexOf(59);//获取;号的位置      return semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri;  }

如果URI中存在;号的话,则会删除其后面的所有字符。/fdsf;/../hello/1/最终也就变成了/fdsf。

ee911c30c5615697cc8d554d46385080.png

1.5.2版本修复

再1.5.2版本中对其进行了修复,获取requestURI的方式从request.getRequestUri直接获取的方式更改为获取request的ContextPath,ServletPath,PathInfo,然后再重新拼接而成。

df9fb6e528d4a96d7ef07c11b4dfd133.png

输入的/fdsf;/../hello/1/,将会被拼接为//hello/1/1再进行URI路径匹配,则无法绕过拦截器。

2b470da5736d119cf53c3cb26eb9fdd9.png

总结

在web容器中,Shiro的拦截器是先与spring(Servlet)执行,两者拦截器对于URI模式匹配的差异,导致Shiro拦截器的绕过,而Shiro对其进行了两次修复,其一为删除requestURI后面的/号进行URL路径匹配,算是简单的修复了添加/号绕过的方式,而后在1.5.2版本中通过requestURI自主拼接的方式修复了/fdsf;/../hello/1/等使用了;号方式的绕过。

而后又会有什么形式的绕过,或者又有什么其它容器导致的差异化绕过。则未可知。

修复方案

1.升级1.5.2版本及以上

2.尽量避免使用*通配符作为动态路由拦截器的URL路径表达式。

参考链接

1.https://github.com/apache/shiro/pull/127

2.https://blog.51cto.com/luchunli/1835108

3.https://issues.apache.org/jira/browse/SHIRO-682

4.https://www.syshlang.com/96db3174/

5.http://shiro-user.582556.n2.nabble.com/Re-ANNOUNCE-CVE-2020-1957-Apache-Shiro-1-5-2-released-td7582136.html

*本文作者:tbag@斗象能力中心TCC,转载请注明来自FreeBuf.COM

f24ad108a4dc229eea87ec9d31762bca.gif

精彩推荐

821383f96bba74eb5e5588905540b92c.png

ca4bf1a679082247b3c4a838fae3fbd7.png

2de06213dedab2a73ddb968e49068ca2.png

97c16b12eb518a1743b81911427ee9ad.png

5413245a3ee769eb5bcbcf67976fbb5f.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值