Shiro安全(四):Shiro权限绕过之Shiro-782

0x00 前言

刚好在学shiro安全,就看了看shiro权限绕过方面的洞

0x01 前置知识

学习一下shiro的配置与使用

https://cloud.tencent.com/developer/article/1643122

0x02 漏洞环境

影响版本:shiro < 1.5.3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2myCmL55-1659858009785)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807142203425.png)]

添加shiro配置

Shiro 中的匹配规则是通过 AntPathMatcher 来进行实现的

? 匹配一个字符
* 匹配一个或多个字符
** 匹配一个或多个目录

ps:这里的规则是 /admin/* 所以 Shiro 并不会对多个目录进行权限校验,例如:/admin/aaa/bbb 这种是不会对其进行权限校验的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MJCtlhSX-1659858009786)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807142401310.png)]

添加一个controller,这个只有在认证后才能访问

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ep1YYhlk-1659858009787)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807142627847.png)]

0x03 漏洞利用

正常情况访问/admin/aaa,因为没有认证所以会弹回登录页

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JHKwOtko-1659858009787)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807142841519.png)]

payload:/admin/Hello%252faaaa

成功绕过shiro认证,进入到controller中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W8wp3MWR-1659858009787)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807142954943.png)]

0x04 漏洞原理

经过调试发现本质其实就是shiro和spring在处理url时候的规则不同导致的认证绕过

通过断点可以看到请求先经过shiro然后再进入spring分发请求到controller

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CUVyceYl-1659858342664)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807154522278.png)]

Shiro层面绕过

Shiro的认证是通过新建filter来实现的,shiro首先会根据uri来获取对应的shiro-filter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1rhULuQN-1659858009788)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807143414926.png)]

跟进getRequestUri,发现uri是通过valueOrEmpty(request.getContextPath()) + “/” + valueOrEmpty(request.getServletPath()) + valueOrEmpty(request.getPathInfo())获得的,而其中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jQnyqxLQ-1659858009788)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807143542302.png)]

对于request.getServletPath()request.getContextPath() 以及 request.getPathInfo(),以 Tomcat 为例的中间件是会对其进行 URL 解码操作的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MdENsvPR-1659858009788)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807143708879.png)]

此时uri为//admin/Hello%2faaaa

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-66TTIkH9-1659858009788)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807143822654.png)]

然后再进入decodeAndCleanUriString函数进行一次解码,他这里会判断是否存在封号,如果存在就截取封号前面的,这样是为了避免http://www.xxxx.com/xxxx;jession=xxxxxx这种情况

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D0Q6v48X-1659858009789)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807143925165.png)]

所以总的来说在getRequestUri函数中,进行了两次url解码操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xWNQKLXK-1659858009789)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807144133458.png)]

返回到最开始的位置,可以看到requestUri为/admin/Hello/aaaa

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9onawq6w-1659858009789)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807144200421.png)]

继续往上层return,来到getChain方法,此时获取到了requestURI,下面就是匹配对应的shiro-filter了。首先获取所有shiro-filter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-getkLC0C-1659858009790)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807144442383.png)]

可以说是一个都匹配不上,最终返回null

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F7RCsJKF-1659858009790)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807144543663.png)]

return到上层,因为返回为null,所以进入了else,最终只返回了默认的 ApplicationFilterChain,在默认的 ApplicationFilterChain 中是没有任何权限校验

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7G1VTtLF-1659858009790)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807144739558.png)]

没有一个shiro-filter被匹配到,至此 Shiro 层面的权限就成功绕过了

Spring层面绕过

接下来就是要能让spring将我们的请求发送到对应的controller

熟悉 Spring 的师傅应该都知道在 Spring 中 DispatcherServlet 是负责请求派发的,即将对应的请求转发到对应的 Controller 来处理,其一个主要的操作是通过 HandlerMappings来将请求映射到处理器Handler。在处理过程中会调用 getHandler 方法来获取一个可以处理该请求的Handler(即与该请求匹配的handler,这个handler最终会调用相应controller)

HandlerMapping在这个SpringMVC体系结构中有着举足轻重的地位,充当着url和Controller之间映射关系配置的角色

http://www.51gjie.com/javaweb/921.html

继续往下debug,来到spring获取Handler的地方

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nwSI7MxT-1659858009790)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807145120095.png)]

在该方法中会获取所有的handlerMappings,通过调用HandlerMapping的getHandler方法来进行判断是否这个Handler可以处理当前请求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lzZZEJ8o-1659858009791)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807145825794.png)]

继续跟进

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QMhoRtFH-1659858009791)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807145932631.png)]

继续跟进来到getHandlerInternal,调用了父类getHandlerInternal,这里获取request的uri,这里也是导致绕过最重要的地方,跟进去看看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NsfyvKlF-1659858009791)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807150005367.png)]

跟进resolveAndCacheLookupPath

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VJse8UAk-1659858009791)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807150049850.png)]

到了spring真正获取uri的地方了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hP2YCXTH-1659858009791)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807150134793.png)]

调用了getPathWithinApplication,调用了getRequestUri

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JHhPq66u-1659858009792)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807150255585.png)]

注意看,这个getRequestUri与shiro中那个getRequestUri不一样,这个是调用了request.getRequestURI()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jsitW6bY-1659858009792)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807150724462.png)]

这个request.getRequestURI()是不会对uri进行解码的,以前的 shiro 使用 request.getRequestURI() 获取用户请求路径,并自行处理,此时 shiro 默认Servlet 容器(中间件)不会对路径进行 URL 解码操作,通过其注释可以看到;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zc0qvAtZ-1659858009792)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807151002301.png)]

但是呢后来在 1.5.2 版本的 shiro 更新中,为了修复 CVE-2020-1957 ,将 request.getRequestURI() 置换为了 valueOrEmpty(request.getContextPath()) + "/" + valueOrEmpty(request.getServletPath()) + valueOrEmpty(request.getPathInfo());而对于 request.getContextPath() 以及 request.getPathInfo(),以 Tomcat 为例的中间件是会对其进行 URL 解码操作的,此时 shiro 再进行 decodeAndCleanUriString,就相当于进行了两次的 URL 解码,而与之后的 Spring 的相关处理产生了差异。

下图也可以看到并没有对uri解码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OkJBlWOx-1659858009792)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807151114474.png)]

此时再传进decodeAndCleanUriString,相当于是只进行了一次解码

回到上一层,可以看到只进行了一次解码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eJ1SmQdp-1659858009792)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807151205098.png)]

重新回到 getHandlerInternal 函数,可以看到 lookupPath 和 request 传入了 lookupHandlerMethod 函数中,这里的 lookupPath 其实就是获取到了我们请求对应的 uri的一次解码,接下来就可以根据lookupPath来匹配Controller的Handler了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0DB0ddqQ-1659858009793)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807151432152.png)]

跟进添加匹配的mapping

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N8IZVuLo-1659858009793)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807151556604.png)]

可以看到第一个mapping为/unauth这个,如果request能和这个mapping符合就匹配上这个mapping,显然是不符合的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MhziDjeg-1659858009793)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807151931719.png)]

跟进getMatchingMapping(判断是否符合)最终来到getMatchingCondition,进行了一系列的判断来到路由匹配

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LlliF0PW-1659858009793)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807151801224.png)]

可以看一下路由/unauth,显然和request中的不匹配

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aZ39ZrZo-1659858009793)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807152054183.png)]

所以返回null

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e2Z7vuxT-1659858009794)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807152120818.png)]

然后一个个mapping和request匹配,最终来到/admin/{name}这个mapping

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gITetrni-1659858009794)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807152343864.png)]

跟进getMatchingMapping

最终来到路由匹配

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GUWzYANb-1659858009794)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807152442016.png)]

spring只对uri一次解码,所以说uri是/admin/Hello%2faaaa,可以和/admin/{name}匹配上

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dgj9jygZ-1659858009794)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807152625846.png)]

匹配成功就添加到 matches 中

上面的这些功能都是为了在所有匹配的Handler之后需要挑选一个最合适的Handler进行请求的处理,获取到合适的 Handler 之后就进行Handler的访问来处理请求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iv1ErMe6-1659858009795)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807152949904.png)]

0x05 总结

总的来说就是shiro和spring对于url的处理方式不同导致的

shiro在获取uri时(为了下一步匹配shiro-filter)对其进行了两次解码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vNbi8NKk-1659858009795)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807153144300.png)]

spring在获取uri时(为了下一步匹配controller)对其进行了一次解码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sJ3taMJX-1659858009795)(C:\Users\91136\AppData\Roaming\Typora\typora-user-images\image-20220807153344089.png)]

所以说/admin/Hello%252faaaa在shiro眼里就是/admin/Hello/aaaa,即并不会触发shiro的认证filter

而在后面的spring眼里是/admin/Hello%2faaaa,刚好匹配上了/admin/{name}这个controller,从而实现了认证绕过

0x06 参考文章

https://www.yuque.com/tianxiadamutou/zcfd4v/emcdeq

https://su18.org/post/shiro-3/#cve-2020-11989

https://cloud.tencent.com/developer/article/1643122

https://www.anquanke.com/post/id/218270#h3-7

http://www.51gjie.com/javaweb/921.html

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值