shiro历史漏洞分析—CVE-2020-1957漏洞

本文深入分析了CVE-2020-1957漏洞,该漏洞源于Shiro与Spring对URL处理的差异,介绍了如何通过添加斜杠或利用分号绕过权限校验,并提供了修复方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声明

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

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

CVE-2020-1957

漏洞信息

漏洞编号:

CVE-2020-1957/CNVD-2020-20984/SHIRO-682
**影响版本:**shiro < 1.5.2
**漏洞描述:**利用Shiro和Spring对URL的处理的差异化,越权并成功访问。
**漏洞补丁:**Commit Commit Commit
**参考:**Shiro权限绕过漏洞详细分析Ruil1n师傅

漏洞分析

SHIRO-682

本漏洞起源于 SHIRO-682。在Spring中,/resource/xx与/resource/xx/都会被截成/resource/xx以访问相应资源;在shiro中,/resource/xx与/resource/xx/被视为两个不同路径。所以在Spring集成shiro时,只需要在访问路径后添加/就存在绕过权限校验的可能。

下面通过复现进行分析(分析、测试版本1.4.2):
首先shiro.ini中[urls]配置如下:

[urls]
# anon:匿名拦截器,不需登录就能访问,一般用于静态资源,或者移动端接口。
# authc:登录拦截器,需要登录认证才能访问的资源。
/login.jsp = authc
/logout = logout
/toJsonPOJO = authc, perms["audit:list"]
/** = anon

输入/toJsonPOJO时,shiro对其进行判断,从shior.ini或其他配置中进行匹配。当匹配到/toJsonPOJO时,匹配成功,跳出循环。

图片

此时,跳转至登陆界面。
输入/toJsonPOJO/时,shiro对其进行判断,当匹配到/toJsonPOJO时,匹配失败,继续匹配;当匹配到/**时,匹配成功,跳出循环。

图片

接着到了springframework中的判断,这里/toJson-POJO/和/toJsonPOJO是可以匹配成功的

图片

此时,成功绕过

图片

其他绕过方式

除了上面的绕过方式,本CVE还存在另一个绕过。利用的是shiro和spring对url中的 ; 处理的差异进行绕过并成功访问。分析、测试版本1.4.2

绕过分析

首先进入Shiro中,首先在

org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver.class#getChain处下断点,进行调试,访问http://localhost:8080/xx/…;/toJsonPOJO

图片

单步调试进入this.getPathWithinApplicat-ion(request),在WebUtils#getPathWithinApplicat-ion()中,通过getContextPath(request),获取到上下文信息后,再用getRequestUri(request)获取具体的uri。进入getRequestUri()方法,在return前,获取到的uri为/xx/…;/toJsonPOJO

图片

接下来分析一下return normalize(decodeAndClean-UriString(request, uri));

首先进入decodeAndCleanUriString

传入的参数uri是/xx/…;/toJsonPOJO,然后通过语句int semicolonIndex= uri.indexOf(59);找出uri中分号的位置,59也就是;的ASCII码

如果uri中有分号,就返回分号前的字段,否则返回整个uri。

图片

接着进入normalize,参数uri已经变成/xx/…,normalize内部对传入的路径进行标准化规范处理,相关操作包括替换反斜线、替换//为/等,最后得到返回的uri

此时return normalize(decodeAndCleanUriString-(request, uri));结果为/xx/…,也就是说getRequestUri(request)获取的uri为/xx/…

图片

图片

一路回到getChain,经过上面的步骤,得到requestURI值为/xx/…,接下来在while循环里使用pathMatches(pathPattern, requestURI)进行权限校验,此时只有/**能够与/xx/…匹配成功,/**是anon权限,不需要登陆就能访问,绕过了/toJsonPOJO的authc权限

图片

此时Shiro部分的权限绕过了,那么Spring部分的路径是怎么匹配的呢?

url经过shiro的处理认证通过后,就会进入spring中进行解析,我们在UrlPathHelper#getLookupPath-ForRequest下断点

图片

先进入getPathWithinApplication(),通过this.get-RequestUri(request)获取uri

图片

获取到的uri值为/xx/…;/toJsonPOJO,在return之前进入decodeAndCleanUriString(request, uri)

图片

传进来的参数uri为/xx/…;/toJsonPOJO,经过removeSemicolonContent(uri)后移除uri中/与/之间的的分号以及分号后面的内容;

经过decodeRequestString(request, uri)后对uri进行解码;经过getSanitized-Path(uri)后将路径中//替换为/。此时返回的uri值为/xx/…/toJsonPOJO

图片

图片

步入getPathWithinServletMapping()后,传入的参数pathWithinApp值为/xx/…/toJsonPOJO。

依次通过UrlPathHelper#getServletPath

HttpServletRequestWrapper#getServletPath

Request#getServletPath获取到我们实际访问的url:http://localhost:8080/toJsonPOJO后返回,最终实现绕过权限访问

图片

图片

经过测试当uri为

123;/…;345/;…/.;/alter/…;/;/;///;/;/;awdwadwa/toJsonPOJO时,Shiro对/123进行权限验证;

图片

Spring的org.springframework.web.util.UrlPathHelper中,getPathWithinApplication(request)值为

/123/…/./alter/…/toJsonPOJO;

图片

图片

this.getPathWithinServletMapping(request, pathWithinApp)值为/toJsonPOJO,可以进行绕过

图片

上面这个payload只能在较低版本的Spring Boot上使用。

根据Ruil1n 师傅介绍:
当Spring Boot版本在小于等于2.3.0.RELEASE的情况下,alwaysUseFullPath为默认值false,这会使得其获取ServletPath,所以在路由匹配时相当于会进行路径标准化包括对%2e解码以及处理跨目录,这可能导致身份验证绕过。

而反过来由于高版本将alwaysUseFullPath自动配置成了true从而开启全路径,又可能导致一些安全问题。

所以在高版本上只能试着寻找逻辑上有没有漏洞,然后进行绕过。比如程序配置了访问路径/alter/** 为 anon,但是指定了其中的一个/alter/page为 authc。这时在不跳目录的情况下,可以使用如下请求绕过:
http://127.0.0.1:8080/alter//;aaaa/;…///;/;/;awdwadwa/page

漏洞修复

先是在Commit的PathMatchingFilter#pathsMatch和PathMatchingFilterCha-inResolver#getChain方法中添加了对访问路径后缀为/的支持

图片

然后在Commit,除了endsWith还添加了equals的判断。是修复由于上一次提交,导致访问路径为/时抛出的异常。

在Commit中,shiro使用request.getContextPath()、request.getServletPath-()、request.getPathInfo()拼接构造uri替代request.getRequestURI()来修复; 绕过

图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值