问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
浅谈Apache shiro 权限绕过漏洞(CVE-2023-34478)
漏洞分析
Apache Shiro之前披露了CVE-2023-34478,对于类似目录穿越的请求,在非springframework特定的场景下可能存在权限绕过的可能。
0x00 前言 ======= Apache Shiro之前披露了CVE-2023-22602,主要是由于 1.11.0 及之前版本的 Shiro 只兼容 Spring 的ant-style路径匹配模式(pattern matching),而高版本的 Spring使用的是PathPatternParser,当使用不同的路径匹配模式时,攻击者在特定的场景下访问可绕过 Shiro 的身份验证。 在修复该漏洞时,主要是通过Spring动态的读取文件留下的扩展接口来将路径匹配模式强制修改为了AntPathMatcher: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-38691d1d34b0a5664ede701b3da69dfd46d7abc3.png) 确实这样的话保证了两者请求解析模式的一致性,避免了解析差异导致的安全问题,但是众所周知,Shiro 是一个功能强大且易于使用的 Java 安全框架,可以提供提供身份验证的功能。那么有没有可能某个框架与Shiro间同样存在类似的解析差异问题导致身份认证绕过呢? ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-14bb8a86adbea33ea76a942428a590bcefc2501c.png) 0x01 漏洞描述 ========= 大致的内容是对于类似目录穿越的请求,在非springframework特定的场景下可能存在权限绕过的可能。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/07/attach-8ae5a175c5163cbd551e99ffa72624ad2618816a.png) 0x02 原理分析 ========= 2.1 shiro请求解析方式 --------------- Shiro中对于URL的获取及匹配在`org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain`方法,其会根据URL路径匹配,解析出ServletRequest请求过程中要执行的过滤器链。其中主要是通过getPathWithinApplication方法获取应用程序内的URI的相对路径: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-b278c69d835360e5d5f404779f346158b85a2caa.png) 具体方法的实现如下,首先通过request.getServletPath()+request.getPathInfo()方法获取URI,然后再调用removeSemicolon和normalize方法处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-31224cc063cbeac100390616ef3e86a439742f7c.png) 在normalize方法中,会处理路径穿越符进行处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-840ac9f9737ba9fc48d2452c65d088f4da5d872a.png) 获取到对应的请求路径后,最终会根据URL进行路径匹配,解析出ServletRequest请求过程中要执行的过滤器链。详细的过程可以参考https://forum.butian.net/share/2231 。 2.2 Jersey请求解析方式 ---------------- 那么Jersey又是如何对请求进行处理的呢? 这里直接看Jersey是如何根据请求路径找到对应的资源的。ApplicationHandler是Jersey的核心组件之一,其handle方法主要是调用this.runtime.process(request)方法来处理HTTP请求: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-0a1d6fe493107d4e7bb96368a16e28e43d6ce2cd.png) process()方法会根据ContainerRequest对象的内容和Jersey应用程序的配置信息,定位到适合处理该请求的资源类或方法,并调用其对应的处理函数来处理客户端请求。 在这个方法中,首先设置了基础 URI,然后使用 `Stages.process()` 方法对请求进行处理,并获取了端点引用。如果无法找到端点,则抛出 `NotFoundException` 异常: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-9d8a6179261507aa4f25b4c61d68c16833842a97.png) 在Stages.process方法中实际上主要是遍历rootStage(其中存储了解析请求的阶段相关的信息,如请求 URI、请求方法、请求头等),调用其apply方法进行处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-761e6146b656e7c206bb8beb3169b34ed4bffa56.png) 跟请求路径相关的主要是`org.glassfish.jersey.server.internal.routing.RoutingStage`,用于解析请求 URI 并将其映射到相应的资源方法或类上。查看其apply方法的具体实现,主要是调用 `_apply()` 方法来查找路由匹配结果,其会返回一个 `RoutingStage.RoutingResult` 对象,包含找到的端点引用以及处理后的请求上下文信息: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-f9c63decda4848d27ebf3f992062d29d89435d3a.png) 在`_apply()` 方法中,使用传入的 `request` 和 `router` 参数调用 `router.apply(request)` 方法,返回一个 `org.glassfish.jersey.server.internal.routing.Router.Continuation` 对象,其中包含了匹配成功的子路由和处理后的请求上下文对象。然后,使用 `continuation.next().iterator()` 方法获取所有匹配成功的子路由,并迭代遍历它们。对于每个子路由,递归调用 `_apply()` 方法以查找匹配的端点引用。 如果找到了匹配的端点引用,则返回一个 `RoutingStage.RoutingResult` 对象,其中包含了找到的端点引用和处理后的请求上下文对象。否则,继续查找下一个子路由,直到找到匹配的端点引用为止: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-e6933c4c33dc8b1f773b6c784f392e5afd8bb702.png) 首先,通过调用`org.glassfish.jersey.server.internal.routing.MatchResultInitializerRouter#apply`将请求对象和根路由器对象打包成一个 `Continuation` 对象,并返回给调用方。通过这个 `Continuation` 对象,Jersey 可以获取与请求相关的所有信息,并继续处理后续的请求逻辑: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-b9eb1440618bb0d71893d9d2e3e45ccec26d3907.png) 在Jersey中,会使用 `RoutingContext` 对象执行路由匹配操作,是一个十分重要的属性,具体看看这里pushMatchResult方法的调用,这里主要是调用org.glassfish.jersey.server.ContainerRequest#getPath对请求的上下文进行处理,如果decode属性为ture(默认为false),会进行一系列的解码处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-d362654858a4be7463add9029bc9df5e7288c4d5.png) 否则会调用encodedRelativePath方法获取当前请求的编码后的相对路径: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-017f1bdaa0eab68d8c4e4eb5f2a5ebdc521bdffb.png) 处理结束后会创建`SingleMatchResult`实例: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-64706a1a96efe8ac9831a29efa645ec97e825ae5.png) 这里会调用stripMatrixParams方法进行额外的处理,这里主要是剔除URI 中的矩阵参数,将 URI 按照斜杠字符进行分割,并将每个分段中的第一个分号字符及其后面的所有内容全部删除。最后,它将所有分段重新拼合起来,并返回处理后的结果: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-c83450f4ea4d4dbf1ab6301c09387a5ae600954a.png) 然后返回对应的结果并push到matchResults列表中: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-a5460f7d7351c95841f2faf34552ac24045cac17.png) 可以看到**Jersey在整个解析过程中并没有对路径穿越符../进行额外的处理**。有点类似Spring高版本PathPattern。 0x03 漏洞复现 ========= 根据前面的分析,Jersey跟Shiro在解析过程中是存在差异的,利用这一点在某种特定情况下会造成身份验证绕过的风险。 以shiro为例,对应的身份认证如下,`/api`目录下的所有接口都需要经过安全认证才能访问: ```Java @Bean ShiroFilterFactoryBean shiroFilterFactoryBean(){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(securityManager()); bean.setLoginUrl("/login"); bean.setSuccessUrl("/index"); bean.setUnauthorizedUrl("/unauthorizedurl"); Map map = new LinkedHashMap<>(); map.put("/doLogin/", "anon"); map.put("/api/**", "authc"); bean.setFilterChainDefinitionMap(map); return bean; } ``` 假设对应的请求资源Resource Class如下: ```Java @GET @Path("/{path : .*}") public Response getUser(@PathParam("path") @Encoded String path) throws IOException { return Response.ok().entity(path).build(); } ``` 正常情况下,在缺少安全认证的情况下访问/api/page,会返回302状态码重定向到login页面: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-f1d4daf93664d814be8538fa5092ef5f751da7bb.png) 结合前面分析的,shiro会解析`..`而Jersey不会的差异,因为可以这里路由匹配的正则表达式为`.*`表示匹配任意字符,那么发送如下请求达到绕过权限控制的效果: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/06/attach-853acc8d3bc008b2a5404fc5e6821ad0131b0c56.png) 0x04 修复方式 ========= 漏洞的修复主要是通过InvalidRequestFilter过滤器进行处理。 可以看到在过滤器的isValid中增加了一个containsTraversal方法: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/07/attach-3f31fdd4c484d961a3c2090760a2849c59d9830c.png) 在该方法中对类似`./`的字符进行了检测,同时也考虑了url编码绕过的问题: ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/07/attach-ae32c4676a7b22b20f6135ff993689f0ac43baea.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2023/07/attach-bb95f09104fae9167cca931f04326dba253ad602.png) 0x05 其他 ======= 作为Shiro的“同僚”SpringSecurity,其也是一个功能强大且高度可定制的身份验证和访问控制框架。针对类似的安全问题,在Spring Security中提供了一个HttpFirewall接口,用于处理掉一些非法请求。目前一共有两个实现类: - StrictHttpFirewall(严格模式) - DefaultHttpFirewall Spring Security缺省使用的是StrictHttpFirewall,其会拦截和处理的一些内容: | 拦截内容 | |---| | 分号(;或者%3b或者%3B) | | 斜杠(%2f或者%2F) | | 反斜杠(\\或者%5c或者%5B) | | %25(URL编码了的百分号%) | | 英文句号.(%2e或者%2E) | 虽然没办法兼顾各个框架间的解析差异,但是确实对一些不合法的http请求path进行拦截能在一定程度上规避掉风险。
发表于 2023-08-07 09:00:01
阅读 ( 8775 )
分类:
漏洞分析
1 推荐
收藏
0 条评论
请先
登录
后评论
tkswifty
64 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!