Apache Shiro是用来做认证和授权的框架,执行身份验证、授权、密码和会话管理。
Shiro主要配合一些容器的使用,如Tomcat、Weblogic等;同时有些框架也会将Shiro集成用来做身份认证和授权,比如:SpringBoot等;
Shiro包括几个重要的类:
Subject:项目,表示需要受Shiro保护的项目;
SecurityManager:安全管理器,管理所有Subject;
Realm:域,用来访问数据,比如访问数据库中的用户密码以及权限角色等信息,使用该类来完成;
Shiro存在一些默认的过滤器
anon:为匿名过滤器
authc:为登录过滤器
学习shiro前要了解他的使用和原理,这样也比较好懂他的成因,下面推荐两个文章;
从Shiro诞生之初,到至今一共存在14个漏洞。以下是shiro官网中的漏洞报告:
1.1.0 之前的 Apache Shiro 和 JSecurity 0.9.x 在将它们与 shiro.ini 文件中的项进行对比之前不会规范化 URI 路径,这允许远程攻击者通过精心设计的请求绕过预期的访问限制,如:/./account/index.jsp
Shiro < 1.1.0
JSecurity 0.9.X
远古版本了属于是,搭个环境给我整了半天。Shiro可以根据ini配置文件去读取用户名密码以及角色权限等信息用来做认证和授权;
[users]
zhang=123,admin
wang=123,admin,vip
# 每一行定义一个用户, 格式是 username = password, role1, role2, ..., roleN
[roles]
admin=user:delete
# 角色在这里定义, 格式是 roleName = perm1, perm2, ..., permN
# 说明1: 权限名可以使用带有层次的命名方式, 使用冒号来分割层次关系, 比如 user:create 或 user:poweruser:update 权限.
# 说明2: user:* 这样的权限, 代表具有 user:create 和 user:poweruser:update 权限.
[urls]
/static/**=anon
/login=anon
/authc/admin/user/delete=perms["user:delete"]
/authc/admin/user/create=perms["user:create"]
/authc/admin/**=roles[admin]
/authc/home=roles[admin,vip]
/authc/**=authc
在request请求到达web容器后,会调用PathMatchingFilterChainResolver的getChain方法获取FilterChain
这个pathMatches方法,其实就是比对你的ini文件中的urls标签下的每一项跟请求的uri是否相等,如果相等,则使用Shiro代理的FilterChain,即ProxiedFilterChain
当执行完Shiro的ProxiedFilterChain后,就执行原来的FilterChain
导致该漏洞的原因就在于,PathMatchingFilterChainResolver的getChain方法中,在获取请求uri时未标准化路径
它使用getPathWithinApplication获取请求URI,在getPathWithinApplication方法中继续调用getPathWithinApplication
然后在WebUtils的getPathWithinApplication中,调用getRequestUri方法
先从javax.servlet.include.request_uri
取,取不到在调用getRequestURI获取请求uri,然后调用decodeAndCleanUriString
在decodeAndCleanUriString中,59为分号,分割分号前的一部分并返回,这是因为一些中间件会在 url 处添加 ;jsessionid
,所以这里对 ;
进行了截取。
全流程看下来,他并没有对路径进行标准化处理,啥是标准化处理,就是去除路径中的/./
、\\
以及其他一些特殊符号。
这就可以绕过权限认证了,当我配置了/index需要认证才能访问,此时我就可以用/./index绕过认证直接访问。
在后续版本增加了标准化处理,在WebUtils的getPathWithinApplication方法中,调用了normalize进行标准化处理
对路径中使用\
的替换为/
,如果路径为/.
返回/
,如果路径不以/
开头,就给他加个/
,然后当路径中有//
,去除一个/
,当路径中有/./
,去掉/.
,当路径中有/../
,将直接移除/..
1.2.3 之前的 Apache Shiro,当使用的 LDAP 服务器启用了无需身份验证即可绑定的功能时,允许远程攻击者通过空用户名或空密码绕过身份验证。
Shiro < 1.2.3
在skis提出的issue中,当在shiro.ini文件中指定了以下几项:
ldapContextFactory = org.apache.shiro.realm.ldap.JndiLdapContextFactory
ldapContextFactory.url = ldap://abc.internal:389/
adRealm = org.apache.shiro.realm.activedirectory.ActiveDirectoryRealm
adRealm.ldapContextFactory = $ldapContextFactory
adRealm.searchBase = "CN=Configuration,DC=abc,DC=internal"
指定从AD域中去获取用户的身份信息完成认证和授权
这个配置文件指定了JndiLdapContextFactory类,这个类的getLdapContext方法是用来获取LDAP上下文的;
getLdapContext方法的执行流程是,将验证信息封装到Hashtable中,然后使用该验证信息去连接LDAP服务器,获取LDAP上下文;
而关键就在于当LDAP服务器允许匿名访问(Anonymous)时,可以使用空用户和空密码登录,同时当LDAP开启任何人bind时,可以使用空用户和任意密码登录。这本质上来说是LDAP服务器的问题,但Shiro还是给了CVE且进行了修复
在新版本中新增了validateAuthenticationInfo方法,但是修了等于没修
他只是判断了用户名不为空且有密码就抛出异常,跟以上两种情景毫无关联,所以说修了等于没修
在Shiro 1.2.5之前,当没有为“remember me”功能配置密钥时,允许远程攻击者执行任意代码或通过请求参数绕过预期的访问限制。
Shiro < 1.2.5
rememberMe功能由RememberMeManager提供,RememberMeManager是个接口,其实现类为
在AbstractRememberMeManager中,他将密钥直接写在了代码中
接下来跟一下调用流程
在DefaultSecurityManager的createSubject方法中调用resolvePrincipals方法解析rememberMe参数,识别用户身份
先从context中解析用户身份,解析不到再调用getRememberedIdentity方法中解析用户身份
DefaultSecurityManager不具备解析rememberMe参数的能力,交由给RememberMeManager去解析,他会调用getRememberedPrincipals方法去解析rememberMe参数
在AbstractRememberMeManager的getRememberedPrincipals方法中调用getRememberedSerializedIdentity获取用户标识
getRememberedSerializedIdentity方法中将rememberMe参数的值进行base64解码,然后返回
返回的字节再调用convertBytesToPrincipals进行转换
先AES解密,然后再反序列化,下面就没必要看了,就是常规的获取反序列化器进行反序列化,这里就造成了反序列化漏洞,可以配合CC链以及其他链去执行任意代码
整个流程梳理下来就是:
若存在RememberMe属性,则获取他的值
将值进行base64解码
然后再进行AES解密
然后进行反序列化
所以只要我们控制了AES密钥,同时服务器存在利用链就可以进行反序列化攻击,执行任意代码
如一开始看到那样,在Shiro 1.2.5之前都是使用了默认密钥,而在1.2.5及后续的版本,都是随机产生的密钥
1.3.2 之前的 Apache Shiro 允许攻击者绕过预期的 servlet 过滤器并通过利用contextPath获得访问权限。
Shiro < 1.3.2
跟CVE-2010-3863有点相似,在PathMatchingFilterChainResolver的getChain方法中,获取requestURI时调用getPathWithinApplication方法
而在getContextPath方法中未标准化路径
进入getContextPath方法查看,他获取contextPath后,直接URL解码并返回,未作标准化路径的操作
返回到getPathWithinApplication方法中,获取完contextPath之后直接截取
若contextPath为/shiro
,当传递的uri为/aaa/../shiro/abc
,此时getContextPath获取的contextPath为/aaa/../shiro
,getRequestUri获取的requestUri为/shiro/abc
,因为/shiro/abc
不以/aaa/../shiro
开头,所以直接返回/shiro/abc
而为什么getContextPath返回的contextPath不是我们设置的/shiro
呢?这是因为在Tomcat的Request的getContextPath方法对/aaa/../shiro/abc
进行截取最后一个/
之前的部分,得到得/aaa/../shiro
,然后标准化后得到/shiro
,比对我们设置的/shiro
,若相等,就返回/aaa/../shiro
正常情况下,我们配置需要登录才能访问的路径都不会带上contextPath
当设置需要登录才能访问的路径为/abc
,而/shiro/abc
成功的进行了绕过
由于匹配不到在Shiro中设置的路径,从而绕过了Shiro过滤器,没有Shiro过滤器的把持下,就不需要进行认证和授权
后续会继续分离/shiro/abc
,进行/abc
路由的访问
在1.3.2及之后的版本中,在WebUtils的getContextPath中,在返回前进行了标准化处理
在1.4.2之前的Apache Shiro,当使用默认的 "rememberMe "配置时,cookies可能容易受到填充攻击。
Shiro < 1.4.2
跟Shiro无关,而是对Shiro采用的加密方式进行的攻击,所以略过,只要了解了Padding Oracle Attack 原理就能理解这个攻击的原理,这里推荐Padding Oracle Attack(填充提示攻击)详解及验证
1.5.2之前的Apache Shiro,当使用Apache Shiro与Spring动态控制器时,特制的请求可能导致认证绕过。
Shiro < 1.5.2
根据提出的issues得知,当访问/index
会被限制,而在后面加上/
,则可以绕过访问限制。
这是由于Spring-Web和Shiro的访问路径的不同处理造成的,在Spring-Web中,/resource/menus
和/resource/menus/
都可以访问资源,而在Shiro中,只有/resource/menus
才会匹配上pathPattern
从而进行身份验证和授权之类的操作。
当访问/index/
时,请求先进入Shiro的filter中,在PathMatchingFilterChainResolver进行路径匹配
由于设置需要身份验证的路径为/index
,这里匹配不到返回null,然后进入Spring-Web的DispatcherServlet中,在DispatcherServlet的doDispatch方法中获取Handler
调用getHandler获取handler,后续在PathPattern#match
方法中对/admin/list/
和 /admin/list
的匹配都会返回 true。
除此之外,还通报了另一个绕过,利用的是Shiro和Spring-Web对url中的;
处理的差别来绕过校验。
Shiro配置中将/abc/admin
设置成了需要认证才能访问
POC:/abc;bbb/admin
在WebUtils的decodeAndCleanUriString方法中,他会截取分号之前的内容返回,即/abc
然后会因为匹配不到Shiro的pathMatches从而绕过Shiro的filter
然后进入Spring-Web的处理
最后返回的uri为/abc/admin,从而成功访问到加了限制的路由
在后续的版本中,在PathMatchingFilterChainResolver的getChain方法中,若路径最后一个符号为/
号,则去掉
同时为了统一,若在配置文件中指定需要认证的路径的最后一个字符/
,也直接去掉
而对于;
的绕过,修复后直接使用contextPath、servletPath和pathInfo进行拼接得到,这些都是通过中间件的调用得到的
直接获取中间件处理好的结果进行拼接,而不是自己去处理,但是有个坑点就是,他拼接完之后又会调用decodeAndCleanUriString方法去截取;
之前的部分再标准化路径返回。
但是对于这个POC/abc;bbb/admin
来说,再用decodeAndCleanUriString方法之前他已经拼接好了路径为/abc/admin
,就不用去截取了,但是若从中间件获取到的路径带有分号的话还会去截取分号之前的部分,造成跟Spring-Web处理不相同而导致的漏洞
1.5.3之前的Apache Shiro,当使用Apache Shiro与Spring动态控制器时,一个特制的请求可能会导致认证绕过。
Shiro < 1.5.3
当Shiro使用Ant风格的路径表达式配置路径时,就有可能导致权限绕过
通配符 | 说明 |
---|---|
? | 匹配任何单字符 |
* | 匹配0或者任意数量的字符 |
** | 匹配0或者更多的目录 |
例如:/admin/*
可以匹配/admin/xxx
,但是不能跨目录,而/admin/**
可以匹配/admin/xxx
也可以匹配/admin/xxx/xxx
,可以跨目录
当配置/admin/*
需要认证才能访问,而访问的uri为/admin/aa/bb
能进行绕过,因为/admin/*
无法跨目录
此次漏洞的原因在于getPathInfo获取路径时会进行解码
解码完再调用decodeAndCleanUriString又会进行一次解码
而进入Spring-Web的处理时,只会将uri解码一次,这就造成了此次漏洞
将斜杆两次编码
/ -> %2f ->%25%32%66
此时配置/admin/*
需要认证才能访问,我们访问/admin/a%25%32%66b
会被Shiro解码成/admin/a/b
,此时就绕过了匹配,当进入Spring容器时,Spring容器只会进行一次解码,将/admin/a%25%32%66b
解码成/admin/a%2fb
,这时候就成功的进行了访问
但是正常人谁会把访问的路由写成/a%2fb
,结果还真有这种情景,就是当把路径作为参数时,
也就是如下情况
@GetMapping(value="/admin/{name}")
@ResponseBody
public void list(@PathVariable String name){
xxx
}
动态接收name的值作为请求参数进行处理
还有一个坑点,是利用;
进行的绕过,也就是1957未修复的坑点
也就是在获取contextPath时,会有带有分号的情况,然后调用decodeAndCleanUriString会截取分号之前的部分,举个例子:
我们配置/xx
需要认证才能访问,我们访问的uri为/;/admin/xx
,则通过request的getContextPath方法获取到的contextPath为/;/admin
,经过decodeAndCleanUriString方法的洗礼,他会截取;
之前的部分,即/
,然后使用/
去匹配需要认证的路由,未匹配上,成功的进行了绕过;而后续在Spring-Web的处理中,他会处理成/admin/xx
,这时候就成功访问到了/admin/xx
的controller且无需认证
原理是在调用Tomcat的Request的getContextPath方法获取contextPath时
在后续的版本中,去除getRequestUri的调用,那么就同时修复了两个绕过
1.6.0之前的Apache Shiro,当使用Apache Shiro时,特制的HTTP请求可能导致认证绕过。
Shiro < 1.6.0
还是利用SpringWeb和Shiro处理方式的差异进行绕过
在Shiro中,先解码、后处理分号,然后再标准化路径
在SpringWeb中,先处理分号,再解码,然后标准化路径
主要是前面两个步骤的差距,可以导致绕过
我们将;
编码成%3b
在Shiro中,他会先解码成分号然后截取分号前的内容
在SpringWeb中,首先他找不到分号,因为分号已经被编码成%3b,相当于他不会处理分号,然后他才将分号解码
所以我们可以使用;
去绕过一些需要认证的路径,只要他截取的分号前的内容设置了不需要验证即可
/admin/*
需要认证才能访问,而我们通过加个%3b,即/admin/%3bxx
,在Shiro中,他会解码成分号,然后截取分号前的内容,即/admin/
,这里就绕过了Shiro的过滤器,在后续Spring-Web处理中,该路径被处理成/admin/;xx
就成功访问到了controller
同样,也是如下场景
@GetMapping(value="/admin/{name}")
@ResponseBody
public void list(@PathVariable String name){
xxx
}
Shiro新增了个全局过滤器,为InvalidRequestFilter
这个类InvalidRequestFilter会检测uri是否存在分号、反斜杠以及非ASCII码字符,若检测到就会返回状态码400,消息为Invalid request
1.7.0之前的Apache Shiro,当与Spring一起使用Apache Shiro时,特制的HTTP请求可能导致认证绕过。
Shiro < 1.7.0
同样还是SpringWeb和Shiro的处理差异造成的
这次是因为.
号造成的绕过,.
号编码为%2e
那么对于Shiro和SpringWeb对待编码后的点号是怎么处理的呢?
在Shiro中,它会先解码成.
,不需要处理分号,然后标准化路径去掉.
而在Spring-Web中,首先无需处理分号,然后将%2e
解码成.
号,在getSanitizedPath也未处理.
号
所以可以使用编码后的点号进行绕过,同样也是设置/admin/*
需要认证才能访问,此时我们加上%2e
,变成/admin/%2e
;
在Shiro中,处理成/admin/
,无法匹配/admin/*
而造成绕过
在Spring中,处理成/admin/.
,成功访问到了/admin
下的路由
同样也是以下场景会造成该漏洞
@GetMapping(value="/admin/{name}")
@ResponseBodypublic
void list(@PathVariable String name)
{
xxx
}
Shiro使用ShiroUrlPathHelper去继承了UrlPathHelper,然后将自己的ShiroUrlPathHelper注入到Spring中,替换掉默认处理的UrlPathHelper
这样使得Spring使用了Shiro的方式去处理路径,统一了处理方式
1.7.1之前的Apache Shiro,当将Apache Shiro与Spring一起使用时,特制的HTTP请求可能导致认证绕过。
Shiro < 1.7.1
再次绕过,这次是通过空格编码进行的绕过,空格编码为%20
获取请求uri
这里只会解码%20
,变成空格
然后处理完,进行路径的匹配,进入pathMatches查看
进入
后面会来到AntPathMatcher#doMatch进行匹配
进入tokenizeToStringArray
进入tokenizeToStringArray
其实就是使用/
分割字符串然后去除空格的这么一个操作,其实总的来说就是去掉空格
而SpringWeb跟Shiro也是一样的处理
设置/admin/*
需要认证才能访问,我们使用/admin/%20
,经过Shiro他会处理成/admin/
,匹配不上/admin/*
从而导致绕过,同样也是以下场景会导致该漏洞
@GetMapping(value="/admin/{name}")
@ResponseBodypublic
void list(@PathVariable String name)
{
xxx
}
在StringUtils#tokenizeToStringArray
方法的第三个参数 trimTokens 为 false,也就是不去除空格
1.8.0之前的Apache Shiro,当与Spring Boot一起使用Apache Shiro时,特制的HTTP请求可能会导致认证绕过。
Shiro < 1.8.0
在上面那个CVE-2020-17523中,后续的1.7.1版本又增加了新的逻辑
如图,它首先会比对原始uri,没比对到再去掉末尾斜杆再进行比对,比对到了就将去掉末尾斜杆uri进行传入
当设置如下配置时,就会产生漏洞
/admin/* authc
/admin/list anon
按理来说,当我们访问/admin
目录下的任何路由(不跨目录)都需要鉴权,所以一般来说没有认证都是访问不了这个/admin/list
的
但是这个漏洞就是可以绕过第一个配置,去访问第二个路由
首先我们传入的poc为/admin/list/
,依据顺序,他首先会匹配第一个,因为原始的uri:/admin/list/
匹配不到/admin/*
,此时会去掉uri的最后一个斜杆进行匹配,即/admin/list
,此时就匹配到了/admin/*
,然后进入filterChainManager.proxy,并将去掉斜杆的uri传入,即/admin/list
进入filterChainManager.proxy进行查看
再进入getChain查看
从map中取,发现刚好有,而对于没有配置的,例如访问/admin/li/
,他取不到,就会抛出异常
回到对/admin/list/
的访问中,在后续他会将代理filterChain返回
代理filterChain有两个filter,第一个为登录过滤器,第二为匿名过滤器
匿名过滤器直接放行,此时就会去访问/admin/list
的controller了,此时就成功的进行了绕过
这个利用条件特别极端,正常人不会这样写配置
/admin/* authc
/admin/list anon
在1.8.0中,传入的参数由requestURINoTrailingSlash变成pathPattern,即/admin/*
而不是/admin/list
而在map中取到的就是需要认证的/admin/*
了
这时就无法绕过第一个配置项去访问第二个配置项了
Apache Shiro在1.9.1之前,RegexRequestMatcher可能被错误配置,导致在一些servlet容器上被绕过。使用RegExPatternMatcher的正则表达式中含有.
的应用程序可能会受到权限绕过的影响。
Shiro < 1.9.1
Shiro有两种表达式可以匹配路径,一种是AntPathMatcher,另一种是RegExPatternMatcher,前面一直都是使用Ant风格,也就是第一种
通配符 | 说明 |
---|---|
? | 匹配任何单字符 |
* | 匹配0或者任意数量的字符 |
** | 匹配0或者更多的目录 |
第二种其实就是正则表达式
这个漏洞很好理解,当配置了需要认证的路径为/admin/.*
,而在正则表达式中元字符.
是匹配除换行符(\n
、\r
)之外的任何单个字符,\r
的URL编码为%0d
,\n
的URL编码为%0a
,所以可以使用/admin/%0d
或者/admin/%0a
,这样就无法匹配/admin/.*
从而绕过认证
新增caseInsensitive,并且默认为false
Pattern.compile第二个参数为32,表示启用DOTALL模式,此时元字符.
会匹配换行符(\n
、\r
)在内的任何单个字符
1.10.0之前的Apache Shiro,Shiro在通过RequestDispatcher进行请求转发(forward)或请求包括(include)时存在认证绕过漏洞。
Shiro < 1.10.0
在进行请求转发或包含时不会进行鉴权,导致绕过
首先添加如下配置:
map.put("/forward","anon");
map.put("/admin/list","authc");
设置/admin/list
需要认证,/forward
不需要认证
如下代码:
@GetMapping("/admin/list")
@ResponseBody
public String list(){
return "访问成功!";
}
@GetMapping("/forward")
public String forward(){
return "forward:/admin/list";
}
直接访问/admin/list
会跳转到登录页面
而访问/forward
访问成功,绕过/admin/list
的鉴权
在Tomcat应用的整个过滤链中,他会调用doFilter去依次执行过滤链中的每个过滤器
而doFilter又会调用internalDoFilter方法
在internalDoFilter中会去调用各个filter的doFilter方法
而在Shiro的doFilter方法中,若在一次请求中已经被Shiro的过滤器过滤过了的话,则不会再调用Shiro的filter再过滤一遍,然后将请求传给其他过滤链中的过滤器
因为请求/forward
的时候,他会走一遍Shiro的过滤器,然后将alreadyFilteredAttributeName设置为shiroFilter.FILTERED,代表已经过滤过
然后在/forward
的controller中,将请求进行转发
而访问/admin/list
时,这两次的路由访问相当于一次请求,因为前面访问/forward
路由时已经经过Shiro的过滤器过滤了一遍,所以此时访问/admin/list
路由,则不会走Shiro的过滤器,从而绕过认证
而在Shiro的1.10.0及以后,出现了个ShiroFilterConfiguration类
这个属性filterOncePerRequest若为false,则代表每次调用都会执行过滤器,这个属性若为true,则代表每次请求都会执行过滤器
而在OncePerRequestFilter的doFilter方法中,新增了个判断
当把1.11.0之前的Apache Shiro与Spring Boot 2.6+ 一起使用时,特制的HTTP请求可能导致认证绕过。当Shiro和Spring Boot使用不同的模式匹配技术时,认证绕过就会发生。Shiro和Spring Boot < 2.6时都默认为Ant风格的模式匹配。
SpringBoot > 2.6 且 Shiro < 1.11.0
SpringBoot 2.6+后,Controller的路径匹配默认使用path_pattern_parser
2.6以前在配置文件中可以这样配置以使用path_pattern_parser
spring:
mvc:
pathmatch:
matching-strategy: path_pattern_parser
2.6之前使用ant_path_matcher
解析Controller的路径,Ant风格估计都很熟,前面说过好几次了,就当作复习一下
通配符 | 说明 |
---|---|
? | 匹配任何单字符 |
* | 匹配0或者任意数量的字符 |
** | 匹配0或者更多的目录 |
他们之间的差别在于:
ant_path_matcher的通配符可以在中间,如:abc/**/xyz
。
path_pattern_parser的通配符只能定义在尾部,如:abc/xyz/**
,且可以使用{*path}
接收多级路由。path
可以随意取名,与@PathVariable
名称对应即可。
首先把环境搭一下
设置/login
和/**
无需认证,/admin/**
需要认证
再添加三个路由
先正常访问/admin/ak
,由于需要认证会跳到登录页面
这时访问/admin/..
,注意!!!!不能直接在浏览器地址栏这样输入然后回车,这里有个坑点,浏览器看到uri有..
会自动将uri变成/
,这个坑点导致我复现半天
抓包,却变成了/
这时候改成/admin/..
就行了
这时候就访问成功了
在PathMatchingFilterChainResolver的getChain方法下个断点
之前说过,调用getPathWithinApplication方法后续会将路径标准化,经过normalize的处理,会将/admin/..
变成/
这时候由于pathMatches无法匹配,而返回null(暂且这么理解),绕过了Shiro的认证
后续进入Spring的处理中,在ServletRequestPathUtils的parseAndCache方法中会获取请求uri,并设置PATH_ATTRIBUTE
属性,进入ServletRequestPath的parse方法查看
获取请求uri
获取到的为/admin/..
,这里其实就是调用中间件的getRequestURI,后面那个if不重要,滤过,RequestPath.parse其实就是将uri包装了一下,包装成DefaultRequestPath类
然后设置属性PATH_ATTRIBUTE,并返回
这个属性很重要,然后就是Spring根据路径去匹配controller了
这里的usesPathPatterns方法就是判断是否用了path_pattern_parser
模式,为true,然后removeAttribute方法移除UrlPathHelper.PATH_ATTRIBUTE属性(这跟刚刚设置的PATH_ATTRIBUTE属性不同),然后进入ServletRequestPathUtils.getParsedRequestPath(request);
在getParsedRequestPath方法里,其实就是获取之前设置的PATH_ATTRIBUTE属性的值,也就是那个包装了uri:/admin/..
的类
回到initLookupPath方法,requestPath.pathWithinApplication().value()这一连串操作其实就是获取uri,这个removeSemicolonContent就是为了移除分号
后续在AbstractHandlerMethodMapping的addMatchingMappings方法中寻找/admin/..
匹配的controller,/admin/**
匹配到了,放入List集合matches中
然后根据/admin/**
路径去寻找Bean
然后就是执行这个Bean
其实就是利用/admin/..
会被Shiro标准化为/
的特性,绕过Shiro的路径匹配,然后由于controller设置了/admin/**
从而匹配到了该路径并执行
在application.yml设置使用ant匹配路径
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
在AbstractHandlerMapping的initLookupPath方法中就会走else
后续就会走到Shiro的获取uri的getPathWithinApplication方法,获取到的uri为/
将Shiro升级到1.11.0以上
继承了EnvironmentPostProcessor
该类的作用是在SpringBoot项目启动之前自定义环境变量,可以在项目启动之前从非标准springboot配置文件中读取相关的配置并填充到springboot上下文中。
CVE-2010-3863因为getRequestUri未标准化路径,可以使用/./
进行绕过
CVE-2014-0074/Shiro-460由于LDAP服务器开启匿名登录或未授权登录,导致可以使用空用户名搭配空密码或空用户名搭配任意密码
CVE-2016-4437/Shiro-550就是著名的反序列化漏洞了
CVE-2016-6802因为getContextPath未标准化路径,可以使用/../
进行绕过
CVE-2019-12422/Shiro-721是对rememberMe功能加密方式的攻击
CVE-2020-1957/Shiro-682是由于SpringWeb和Shiro处理方式不同,导致可以使用加路径末尾加斜杆或路径中加分号进行绕过
CVE-2020-11989/Shiro-782是由于SpringWeb和Shiro处理方式不同,导致可以使用斜杆双编码或加分号进行绕过
CVE-2020-13933是由于SpringWeb和Shiro处理方式不同,导致可以使用分号编码进行绕过
CVE-2020-17510是由于SpringWeb和Shiro处理方式不同,导致可以使用点号编码进行绕过
CVE-2020-17523是由于SpringWeb和Shiro处理方式不同,导致可以使用空格编码进行绕过
CVE-2021-41303/Shiro-825是由于新增逻辑的错误,导致可以绕过第一个需要认证的路径而访问第二个匿名路径
CVE-2022-32532是由于Shiro正则代表路径,且路径中含有.
号,导致可以使用%0d
或%0a
进行绕过
CVE-2022-40664是由于Shiro在进行请求转发或包含时未进行鉴权导致绕过
CVE-2023-22602是由于SpringWeb和Shiro使用的路径处理模式不同,导致可以使用/..
进行绕过