Apache Solr 身份验证绕过漏洞分析(CVE-2024-45216)
2024-12-17 04:0:0 Author: mp.weixin.qq.com(查看原文) 阅读量:1 收藏

1. 前言

官方公告:            
https://solr.apache.org/security.html#cve-2024-45216-apache-solr-authentication-bypass-possible-using-a-fake-url-path-ending
https://issues.apache.org/jira/browse/SOLR-17417

漏洞描述:
Apache Solr 中存在不正确的身份验证漏洞。使用 PKIAuthenticationPlugin 的 Solr 实例(在使用 Solr 身份验证时默认启用)容易受到身份验证绕过的影响。任何 Solr API URL 路径末尾的假结尾将允许请求跳过身份验证,同时保持与原始 URL 路径的 API 契约。这个假结尾看起来像一个不受保护的 API 路径,但它在身份验证之后但在 API 路由之前在内部被剥离。

影响版本:
Apache Solr 5.3.0 ~ 8.11.4 之前版本
Apache Solr 9.0.0 ~ 9.7.0 之前版本

2. 环境搭建

9.x.x 版本下载地址:https://archive.apache.org/dist/solr/solr/
8.x.x 及以前版本下载地址:
https://archive.apache.org/dist/lucene/solr/

官方教程文档:https://solr.apache.org/guide/8_11/

本次复现使用 Apahce solr 8.11.3,jdk 11.0.16。

在bin目录下运行以下命令即可启动或停止 solr,-c是以 SolrCloud 模式启动solr,-p指定启动端口:

solr -p 8983      #启动            solr stop -p 8983       #停止            solr -c -p 8983     #以 SolrCloud 模式启动            solr -c -p 8983 -a "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"       #启动并开启远程调试

浏览器访问 http://localhost:8983/solr/ ,solr 成功运行。

这个时候访问/solr/admin/info/properties,不需要登录,会显示配置信息。

要还原漏洞环境,我们需要自己配置身份验证和授权。Solr 所有身份验证、授权和审计日志插件等相关配置(包括用户和权限规则)都存储在 security.json 文件中,在 SolrCloud 模式中需要将 security.json 上传至 ZooKeeper。如果本地没有搭建 ZooKeeper 服务,可以使用 Solr 自带的嵌入式 ZooKeeper,默认端口为 9983。

自定义一个 security.json ,这里直接使用官方提供的配置。           
authentication 为认证部分:           
    - blockUnknown 为 true,未经认证的请求不允许通过;
    - 指定 solr.BasicAuthPlugin 插件类为solr提供身份验证;
    - 定义用户名为 solr 的用户,密码通过加密存储。
authorization 为授权部分:           
    - 指定 solr.RuleBasedAuthorizationPlugin 插件类为 solr 提供授权;
    - permissions 定义操作权限,权限名称为 security-edit,表示允许编辑安全配置。拥有该权限的角色是 admin;
    - 定义用户与角色的映射关系,表示 solr 用户拥有 admin角色的权限。
{            "authentication":{               "blockUnknown": true,               "class":"solr.BasicAuthPlugin",               "credentials":{"solr":"IV0EHq1OnNrj6gvRCwvFwTrZ1+z1oBbnQdiVC3otuq0= Ndd7LKvVBAaZIF0QAVi1ekCfAJXr1GGfLtRUXhgrF8c="},            },            "authorization":{               "class":"solr.RuleBasedAuthorizationPlugin",               "permissions":[{"name":"security-edit",                  "role":"admin"}],               "user-role":{"solr":"admin"}                }            }

先以 SolrCloud 模式启动 Solr,执行下面的命令将自定义的 security.json 文件上传到 ZooKeeper。           

solr zk cp -z localhost:9983 file:security.json zk:/security.json
上传成功后重新启动 Solr,身份验证生效,访问主页和 /solr/admin/info/properties 就需要登录了。

这样漏洞环境就搭好了。

3. 漏洞复现

在未登录的情况下访问/solr/admin/info/properties会返回401。

在 url 后面添加:/admin/info/key,向请求头中添加SolrAuth头,即可绕过身份验证,成功返回配置信息。

4. 漏洞分析

IDEA中添加配置,开始调试。
先看看未登录情况下的身份认证流程。
在 SolrDispatchFilter.doFilter() 断点,调用 authenticateRequest() 进行身份认证,如果返回 true,则说明认证通过。
跟进 authenticateRequest(),获取到认证插件为 security.json 中指定的 BasicAuthPlugin。
下面对请求路径进行判断,如果路径匹配
/admin/info/key,则直接返回 true 。
如果请求头中含有 SolrAuth 或 SolrAuthV2,则采用 PKIAuthenticationPlugin 认证插件。
这些条件都不满足,调用当前 BasicAuthPlugin 插件的 authenticate() 方法进行认证,如果认证通过,则将 isAuthenticated 设为 true,返回认证成功的结果。
跟进到 BasicAuthPlugin.doAuthenticate(),判断了请求头中的 Authorization 字段,由于我们并没有登录信息,所以认证不通过,返回 false。
再来看看绕过后的认证流程。
同样进入到 SolrDispatchFilter.authenticateRequest(),这时请求头中含有
SolrAuth 字段,所以认证插件采用 PKIAuthenticationPlugin。
跟进到 PKIAuthenticationPlugin.doAuthenticate() 进行认证,这里直接通过判断 URI 只要以/admin/info/key结尾就返回 true,所以成功通过 PKIAuthenticationPlugin 插件的认证。
SolrDispatchFilter.authenticateRequest() 也返回 true。
继续跟进到 HttpSolrCall.init(),这里判断了路径中是否含有:号,有的话就只保留:号前的部分,于是 path 就变成了/admin/info/properties,这样就能获取到其对应的处理器。
处理器不为 null,就给 HttpSolrCall 对象的 requestType 赋值为 RequestType.ADMIN,给 action 赋值为 Action.ADMIN,表示授予 admin 角色权限。
接着进入 HttpSolrCall.authorize(),调用 RuleBasedAuthorizationPluginBase.authorize() 进行授权,因为上面将 requestType 赋值为了 RequestType.ADMIN,所以这里进入 if 分支。mapping 是 security.json 中授予 admin 角色 security-edit 允许编辑安全配置的权限。
跟进 checkCollPerm(),mapping 中没有找到/admin/info/properties的授权规则,继续跟进 checkPathPerm(),返回 NO_PERMISSIONS_FOUND 标识。
接着获取了默认权限列表{"name":"security-edit","role":"admin"},继续检查权限列表是否适用与当前请求。
遍历权限列表,到 predefinedPermissionAppliesToRequest(),context.getHandler() 不是 PermissionNameProvider 类型,不适用于当前权限,返回 false。
最后还是返回 NO_PERMISSIONS_FOUND 标识,状态码为 200。
HttpSolrCall.authorize() 返回 null,表示授权成功,继续处理流程。

5. 补丁分析

在 8.11.4 版本中,将 PKIAuthenticationPlugin.doAuthenticate() 中判断路径是否以/admin/info/key结尾的代码删掉了,所以当使用 PKIAuthenticationPlugin 插件进行身份认证时,这一步不会返回 true,也就无法再利用/admin/info/key结尾来绕过身份认证。
HttpSolrCall.init() 中截取:号前路径的代码也被删除了,URL路径假结尾无法被剥离,就无法获取到正确的处理器,不会进入下面的 if 分支,就无法被授予 ADMIN 角色权限。

文章来源: https://mp.weixin.qq.com/s?__biz=Mzg4Nzc3MTk3Mg==&mid=2247488827&idx=1&sn=f3086118f07d69c4ba6746464f993e16&chksm=cf841310f8f39a06855e329956e6033407a0a66e4e90bb99d1ad3153c4241036054b9fa9ff7a&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh