Apache Solr 身份认证绕过漏洞 (CVE-2024-45216) 分析与新发现
chaosnaix 发表于 陕西 漏洞分析 1073浏览 · 2024-11-12 14:32

1、漏洞概要

Apache Solr 是Apache Lucene项目的开源企业搜索平台。

前两天Apache Solr 发布了一个身份认证绕过漏洞 CVE-2024-45216。从官方的描述中可以知道,漏洞是Solr 实例使用了PKIAuthenticationPlugin来进行鉴权,就可以在任何 Solr API URL 路径末尾构造一个特殊的结尾跳过身份验证。看着还怪神奇的,下面就详细看看这个漏洞是怎么个事。

影响版本
Apache Solr < 8.11.4
Apache Solr < 9.7.0

参考
https://solr.apache.org/security.html#cve-2024-45216-apache-solr-authentication-bypass-possible-using-a-fake-url-path-ending

2、漏洞环境

这里环境搭建其实网上很多不必要太多赘述。

但值得注意的是,这里需要启用PKIAuthenticationPlugin来进行鉴权。根据官方的说法这种配置常用于 SolrCloud 模式的集群中,所以这里方便起见就可以用solr和zookeeper简单搭建一个集群,集群搭建的教程很多这里不过多赘述。

按照官方默认方式启动后,solr的接口都是直接未授权访问的。

然后重点是鉴权部分

  1. 需要制作一个 security.json 配置文件,这里用官方给的demo就可以。
{
"authentication":{
   "class":"solr.BasicAuthPlugin",
   "credentials":{"solr":"IV0EHq1OnNrj6gvRCwvFwTrZ1+z1oBbnQdiVC3otuq0= Ndd7LKvVBAaZIF0QAVi1ekCfAJXr1GGfLtRUXhgrF8c="},
},
"authorization":{
   "class":"solr.RuleBasedAuthorizationPlugin",
   "permissions":[{"name":"security-edit",
      "role":"admin"}],
   "user-role":{"solr":"admin"}
}}
  1. 使用solr命令加载 security.json 配置文件
>bin/solr zk cp ./security.json zk:security.json -z localhost:2181

配置完以后,这个时候就需要认证了

3、漏洞复现

根据公开出来的poc,大概就是这样,需要在URL结尾加上:/admin/info/key 这个结尾,然后需要配置 SolrAuth header。

GET /solr/admin/info/properties:/admin/info/key HTTP/1.1
Host: 127.0.0.1:8983
SolrAuth: 11
Connection: close

比如刚才我们无法访问的接口,现在都可以直接访问和操作。

当然由于未授权,除了可以泄漏一些敏感信息,后续还可以有更多利用,比如获取和修改core的配置,基本上各种可以通过接口完成的工作都可以通过这个来绕过。

看到这就有个很自然的疑问,这是如何绕过的?下面就简单来分析分析

4、分析

通过版本间的比对,可以看到官方修复 commit 主要为这里https://github.com/apache/solr/commit/bd61680bfd351f608867739db75c3d70c1900e38

修复重点在 PKIAuthenticationPlugin.javaHttpSolrCall.java 中,这解析请求和鉴权的重点逻辑也就在这两个的代码中。

要点-1: PKIAuthenticationPlugin

在 solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java 中,主要的修复方式是删除了如下代码:

String requestURI = request.getRequestURI();
if (requestURI.endsWith(PublicKeyHandler.PATH)) {
  assert false : "Should already be handled by SolrDispatchFilter.authenticateRequest";

  numPassThrough.inc();
  filterChain.doFilter(request, response);
  return true;
}

这段代码从请求中获取 requestURI,检查其是否以 PublicKeyHandler.PATH 结尾。如果满足条件,调用 filterChain.doFilter(request, response)继续拦截并处理请求,并返回 true通过认证。

这里 PublicKeyHandler.PATH 可以看到就是我们加的后缀 /admin/info/key

但似乎缺少了':' ?这个冒号是起的什么作用?

后续会看到

要点-2: HttpSolrCall

在 solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java 中,对以下代码进行了删除

int idx = path.indexOf(':');
if (idx > 0) {
  // save the portion after the ':' for a 'handler' path parameter
  path = path.substring(0, idx);
}

对以下进行了修改

// 原始代码
idx = path.indexOf('/', 1);

// 修改后
int idx = path.indexOf('/', 1);

这里的主要逻辑就是检查路径中是否包含冒号 : 字符,如果存在就截取 ':' 之前的字符串作为新的 path为请求路径,并将 ':' 之后的部分保存为 handler 路径参数。

从上述流程可以大概感觉到,就是这个特性,导致了鉴权逻辑中的路径和实际访问时的路径的差异,最终造成了鉴权的绕过。

要点-3: SolrAuth header

但还有一个疑问,为什么必须得加上 SolrAuth 头才可以利用。

这个得看回到鉴权前的流程,当我们的代码走到 org.apache.solr.servlet.SolrDispatchFilter#authenticateRequest 时,我们可以在这里看到进行了判断,只有当 header 为 PKIAuthenticationPlugin.HEADER 或 PKIAuthenticationPlugin.HEADER_V2 时,且cores.getPkiAuthenticationSecurityBuilder() 不为空,当前的鉴权插件才是 PKIAuthenticationPlugin,不然就是BasicAuthPlugin.

这里headerV2headerV1 的值即为 "SolrAuth" 和 "SolrAuthV2"

SolrAuth header 的新发现

在进一步跟进的时候,可以看到 PKIAuthenticationPlugin#doAuthenticate 中也有一段校验的逻辑,从这里看到这里的逻辑其实headerV2headerV1 都是可以通过的,而并不影响的我们

所以验证一下,也确实能达到一样的效果

小结

简单总结一下,也就是说由于插件中校验的路径和负责解析url的逻辑产生了差异,导致只要结尾是:/admin/info/key,并且再加上"SolrAuth" header强制使用PKIAuthenticationPlugin, 就可以绕过鉴权直接访问操作API。

调用过程大概如下:

先是通过 org.apache.solr.servlet.SolrDispatchFilter#dispatch 来分发请求,然后经过

  • org.apache.solr.servlet.SolrDispatchFilter#authenticateRequest
  • org.apache.solr.security.AuthenticationPlugin#authenticate
  • org.apache.solr.security.PKIAuthenticationPlugin#doAuthenticate

最终来到 PKIAuthenticationPlugin,进行鉴权。
最后在 org.apache.solr.servlet.HttpSolrCall#call 去解析响应被分割前的路径。

0 条评论
某人
表情
可输入 255