路径遍历漏洞 (Path Traversal) 详细分析

环境部署参考官方文档:https://docs.astrbot.app/deploy/astrbot/docker.html

漏洞基本信息

  • 漏洞类型: 路径遍历 (Path Traversal/CWE-22)

  • 安全等级: 高危

  • 是否需要认证: 否

  • 路由地址: /api/chat/get_file

  • HTTP方法: GET

漏洞点分析

1. 漏洞核心代码位置

漏洞存在于 astrbot/dashboard/routes/chat.py 文件的第58-73行 get_file() 方法中:

async def get_file(self):
    filename = request.args.get("filename")  # 从URL参数获取文件名
    if not filename:
        return Response().error("Missing key: filename").__dict__

    try:
        # 漏洞点:直接拼接用户输入的文件名到基础路径
        with open(os.path.join(self.imgs_dir, filename), "rb") as f:
            if filename.endswith(".wav"):
                return QuartResponse(f.read(), mimetype="audio/wav")
            elif filename.split(".")[-1] in self.supported_imgs:
                return QuartResponse(f.read(), mimetype="image/jpeg")
            else:
                return QuartResponse(f.read())
    except FileNotFoundError:
        return Response().error("File not found").__dict__

2. 基础路径解析

self.imgs_dir 在类初始化时定义于第37行:

self.imgs_dir = os.path.join(get_astrbot_data_path(), "webchat", "imgs")

get_astrbot_data_path() 函数在 astrbot/core/utils/astrbot_path.py 中定义:

def get_astrbot_data_path() -> str:
    """获取Astrbot数据目录路径"""
    return os.path.realpath(os.path.join(get_astrbot_root(), "data"))

def get_astrbot_root() -> str:
    """获取Astrbot根目录路径"""
    if path := os.environ.get("ASTRBOT_ROOT"):
        return os.path.realpath(path)
    else:
        return os.path.realpath(os.getcwd())

因此,基础路径通常是程序运行目录下的 data/webchat/imgs 目录。

而请求的路由是在路径白名单里的

# astrbot/dashboard/server.py
allowed_endpoints = ["/api/auth/login", "/api/chat/get_file", "/api/file"]

漏洞成因

  1. 缺乏输入验证: 代码直接使用 request.args.get("filename") 获取用户输入,未对文件名进行任何安全检查

  2. 路径拼接缺陷: 使用 os.path.join(self.imgs_dir, filename) 直接拼接用户输入,未防止目录遍历字符

  3. 无访问控制: 该接口未要求身份验证,任何人都可以访问

漏洞利用原理

当用户输入包含 ../ 字符串时,操作系统会将其解释为”上级目录”,从而可以跳出预设的 imgs_dir 目录范围。

例如:

  • 基础路径:/app/data/webchat/imgs/

  • 用户输入:../../../main.py

  • 最终路径:/app/data/webchat/imgs/../../../main.py/app/main.py

正确的利用Payload

根据实际测试,正确的利用需要足够的 ../ 来回到项目根目录:

GET /api/chat/get_file?filename=../../../main.py

或者为了确保能够访问到系统根目录的文件:

GET /api/chat/get_file?filename=../../../../../etc/passwd

思路扩展

任意文件读如何扩大危害呢,其实可以考虑一下读取cmd_data.json 这里边是存密码hash过后的值的,而且通过抓包可以很清楚知道,登陆的时候密码直接就是密文,所以我们抓取到密文之后直接就可以登录,都不需要进行任何的解密动作

修复建议

  1. 输入验证: 对用户输入的文件名进行严格验证,禁止包含路径遍历字符

  2. 路径规范化: 使用 os.path.realpath() 获取绝对路径后,检查是否仍在允许的目录范围内

  3. 白名单机制: 仅允许访问预定义的文件扩展名和文件名

  4. 访问控制: 对此接口添加身份验证要求

感觉这个漏洞的成因和CVE-2025-26319特别像,都是有白名单的接口,然后里面未校验。