• 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

  • 相关阅读:
    力扣-1984. 学生分数的最小差值
    基于Python实现的简易微信系统
    Vite打包优化插件
    Druid 数据库连接池 详解
    OSPF —— OSPF邻居状态机(工作机制 )
    Springboot楼盘在线销售平台7txdy计算机毕业设计-课程设计-期末作业-毕设程序代做
    基于工步执行的附加超时机制的一种模式
    Babylonjs学习笔记(一)——搭建基础场景
    css3 2d转换transform详细解析与代码实例transform
    【ICer的脚本练习】tcl语法熟悉和工具tcl的实例
  • 原文地址:https://blog.csdn.net/weixin_43263451/article/details/126212097