shiro历史漏洞分析

admin 2022年9月28日10:44:36评论31 views字数 5889阅读19分37秒阅读模式

出品|先知社区(ID:alter99)


声明

以下内容,来自先知社区的alter99作者原创,由于传播,利用此文所提供的信息而造成的任何直接或间接的后果和损失,均由使用者本人负责,长白山攻防实验室以及文章作者不承担任何责任。


CVE-2020-17510

漏洞信息

漏洞编号:CVE-2020-17510 / CNVD-2020-60318
影响版本:shiro < 1.7.0
漏洞描述:第三种AntPathMatcher的绕过方式
漏洞补丁:Commit


漏洞分析

这个漏洞还是对AntPathMatcher的继续绕过,在CVE-2020-11989和CVE-2020-13933分别尝试了/的双重URL编码和 ; 的URL 编码绕过,归根到底这种方式还是因为Shiro与Spring对URI处理的差异化导致的。那么字符 . 是不是也可以进行绕过呢?其实是可以的(测试环境Shiro 1.6.0,SpringBoot 2.5.3),还是添加如下配置和Controller

map.put("/hello/*", "authc");@GetMapping("/hello/{name}")public String hello(@PathVariable String name) {    return "hello";}

当Shiro获得的uri为/hello时,是无法和/hello/*匹配的,所以就在/hello后面加上%2e,这样Shiro解码之后变成/hello/.,然后路径标准化成为/hello,绕过身份验证

shiro历史漏洞分析

对于Spring来说,正如之前讲的,Spring Boot 版本在小于等于 2.3.0.RELEASE时,会对uri进行解码然后路径标准化,这样得到的路径为/hello,没有页面与之匹配。所以只有当 Spring Boot 版本在大于 2.3.0.RELEASE时标准化路径后/hello/%2e,然后解码/hello/.

shiro历史漏洞分析

shiro历史漏洞分析

下面的payload都可以使用:

/%2e/%2e//%2e%2e/%2e%2e/


漏洞修复

在Commit中发现org.apache.shiro.spring.web下新增了ShiroUrlPathHelper类,属于UrlPathHelper的子类,重写了getPathWithinApplication和getPa-thWithinServletMapping两个方法

shiro历史漏洞分析

通过相关配置后,Spring就会使用Shiro的UrlPathHelper,这样两者判断逻辑一致,就不存在因差异性问题而导致的绕过了。


其实我认为1.7.1才算真正的更新,因为它是依次对原uri和去除uri尾部斜线的uri进行验证,这样就可以避免因直接去除尾部uri导致/hello和/hello/*不匹配而导致的绕过问题。



补丁问题

问题一

根据官方发布的公告,发现其实需要配置shiro-spring-boot-web-starter才有效

if you are NOT using Shiro’s Spring Boot Starter(`shiro-spring-boot-web-starter`), you must configure add theShiroRequestMappingConfig auto configuration[1] to your application orconfigure the equivalent manually[2].[1] https://shiro.apache.org/spring-framework.html#SpringFramework-WebConfig[2]https://github.com/apache/shiro/blob/shiro-root-1.7.0/support/spring/src/main/java/org/apache/shiro/spring/web/config/ShiroRequestMappingConfig.java#L28-L30

由于我导入的dependency如下

<dependency>    <groupId>org.apache.shiro</groupId>    <artifactId>shiro-web</artifactId>    <version>1.6.0</version></dependency><dependency>    <groupId>org.apache.shiro</groupId>    <artifactId>shiro-spring</artifactId>    <version>1.6.0</version></dependency>

如果直接将版本升为1.7.0的话,其实并没有触发更新,原payload还是可以绕过。
只有按照上面官网所述的两种配置方式修改后,才能防御成功


问题二

在旧版的SpringBoot 中,当我们需要获取当前请求地址的时候,直接通过如下方式获取:

//org.springframework.web.servlet.handler#getHandlerInternalString lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);

但是在新版Spring里边,通过如下方式获取

String lookupPath = this.initLookupPath(request);

initLookupPath()代码如下:

protected String initLookupPath(HttpServletRequest request) {    if (this.usesPathPatterns()) {        request.removeAttribute(UrlPathHelper.PATH_ATTRIBUTE);        RequestPath requestPath = ServletRequestPathUtils.getParsedRequestPath(request);        String lookupPath = requestPath.pathWithinApplication().value();        return UrlPathHelper.defaultInstance.removeSemicolonContent(lookupPath);    } else {        return this.getUrlPathHelper().resolveAndCacheLookupPath(request);    }}

如果this.usesPathPatterns() == true的话,就可以绕开问题一中我们配置的ShiroUrlPathHelper

shiro历史漏洞分析

此时也成功绕过。

shiro历史漏洞分析

所以这就存在一个矛盾:只有Spring Boot 版本在大于 2.3.0.RELEASE才能触发这个漏洞,修复之后由于版本问题,SpringBoot又不走那条语句。


另外在配置的时候,当Spring Boot版本在小于等于2.3.0.RELEASE,如2.1.5.RELEASE,时,this.get-UrlPathHelper()并不是ShiroUrlPathHelper,不清楚是不是配置问题还是版本兼容问题。

shiro历史漏洞分析



CVE-2020-17523

漏洞信息

漏洞编号:CVE-2020-17523 / CNVD-2021-09492
影响版本:shiro < 1.7.1
漏洞描述:Shiro 1.7.1 之前的版本,在将 Shiro 与 Spring 结合使用时,特制的 HTTP 请求可能会导致身份验证绕过。
漏洞补丁:Commit



漏洞分析

如CVE-2020-17510那样,这个漏洞可以使用空格%20进行绕过。

我们输入路径为http://localhost:8080/hello/%20,进入getChain,经过路径获取后要进行权限的匹配与验证

shiro历史漏洞分析

注意,获取的路径后面有空格,这里主要看一下/hello/和/hello/*比较时发生了什么经过:

pathMatches(pathPattern,requestURI)-> pathMatcher.matches(pattern,path)->match(pattern,source)-> doMatch(pattern, path, true) 来到了主要的判断方法doMatch()。


其中StringUtils.tokenizeToStringArray()方法是将它的参数,也就是传进来的两个路径拆解成字符串数组,然后进行比较。进入方法,可以看到当对空格进行转换时,直接trim为空。

shiro历史漏洞分析

shiro历史漏洞分析

这样就导致与shiro中的配置本意想违背,导致绕过。

shiro历史漏洞分析

然后在Spring中的处理时,uri又包含空格,这样就能访问到/hello/%20页面

shiro历史漏洞分析



漏洞修复

在Commit中,主要修复点AntPathMatcher.java,在tokenizeToStringArray方法中加了false和true两个参数

shiro历史漏洞分析

可以看到,当第三个参数为false时,即trimTokens为false,此时就不会对token进行trim。

shiro历史漏洞分析



CVE-2021-41303

漏洞信息

漏洞编号:CVE-2021-41303 / SHIRO-825
影响版本:shiro < 1.8.0
漏洞描述:1.8.0 之前的Apache Shiro,在Spring Boot中使用Apache Shiro 时,特制的HTTP请求可能会导致身份验证绕过。用户应该更新到Apache Shiro 1.8.0。
漏洞补丁:Commit
参考:threedr3am师傅


漏洞分析

根据threedr3am师傅博客提供的方向,看了一Shiro1.7.1前后PathMatchingFilterChainResolver-#getChain的对比

shiro历史漏洞分析

shiro历史漏洞分析

发现在1.7.1版本中,先是对pathPattern和requestURI进行比较,比较成功,返回:

filterChainManager.proxy(originalChain, pathPattern);

否则对删除尾部斜线的pathPattern和requestURI进行比较,比较成功,跳出循环,返回:

filterChainManager.proxy(originalChain, requestURINoTrailingSlash);

但是正常访问,都会返回第一个proxy,什么时候才能绕过第一个比较并符合第二个比较呢?
可以看到,两者差别是对uri尾部斜线的处理,所以当在uri尾部加一个/,就会进入第二种比较方式。

shiro历史漏洞分析

结合之前的多次调试再根据threedr3am师傅博客中的认证,可以知道shiro的认证鉴权会根据配置的先后顺序去依次实施,所以当我有如下配置时:

map.put("/admin/*", "authc");map.put("/admin/page", "anon");

循环中先匹配到/admin/*(这里是通过while语句对去除尾部斜线的uri进行匹配)然后跳出循环进入到

filterChainManager.proxy(originalChain, requestURINoTrailingSlash);,


注意,这里真正的参数就是去除尾部斜线的uri,也就是/admin/page,所以在DefaultFilterChain-Manager#getChain中得到的权限是anon,这样就达到绕过目的。

shiro历史漏洞分析

shiro历史漏洞分析


漏洞修复

直接将filterChainManager.proxy的第二个参数改为pathPattern,直接传配置中的uri了

shiro历史漏洞分析



CVE-2022-32532

漏洞信息

漏洞编号:CVE-2022-32532
影响版本:shiro < 1.9.1
漏洞描述:在1.9.1之前的Apache Shiro中,RegexRequestMatcher可能会被错误配置,从而在某些servlet容器上被绕过。应用程序使用RegExPatternMatcher与.的正则表达式可能容易被授权绕过。
漏洞补丁:Commit
参考:4ra1n师傅


漏洞分析

这是最新的一个洞,看Shiro发布的公告显示,是由于RegexRequestMatcher的错误配置导致的问题。


简单了解了一下,RegexRequestMatcher和Ant-PathMatcher类似,都是Shiro用于路径匹配的配置,只是RegexRequestMatcher需要用户自己配置。


根据4ra1n师傅的分析,可以知道,正常正则表达式.并不包含r和n字符

shiro历史漏洞分析

修改成如下代码就可修复问题

// flag为Pattern.DOTALL时,表达式 .可以匹配任何字符,包括行结束符。Pattern pattern = Pattern.compile(regex,Pattern.DOTALL);

shiro历史漏洞分析

那么回头看一下RegexRequestMatcher用于匹配的代码

public boolean matches(String pattern, String source) {    if (pattern == null) {        throw new IllegalArgumentException("pattern argument cannot be null.");    } else {        Pattern p = Pattern.compile(pattern);        Matcher m = p.matcher(source);        return m.matches();    }}

可以发现,当pattern存在带.的正则表达式并且source中存在r或n字时,此时判断错误。


此时我们在配置完RegexRequestMatcher之后增加如下Controller

@RequestMapping(path = "/alter/{value}")public String alter(@PathVariable String value) {    System.out.println("绕过成功");    return "绕过成功"+value;}

增加如下配置

//myFilter.java中设置成需要权限manager.addToChain("/alter/.*", "myFilter");
这样正常访问/alter/aaa是被拒绝的,但是当访问/alter/a%0aaa或/alter/a%0daa时就会绕成验证,访问成功

shiro历史漏洞分析

shiro历史漏洞分析

shiro历史漏洞分析

这个洞限制还是比较多的,既要服务器配置了RegExPatternMatcher,又要设置带有.的正则表达式


漏洞修复

在Commit可以看到,对compile方法设置了flag

shiro历史漏洞分析


shiro历史漏洞分析
shiro历史漏洞分析
shiro历史漏洞分析

▇ 扫码关注我们 ▇

长白山攻防实验室

学习最新技术知识


原文始发于微信公众号(长白山攻防实验室):shiro历史漏洞分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年9月28日10:44:36
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   shiro历史漏洞分析http://cn-sec.com/archives/1320974.html

发表评论

匿名网友 填写信息