安全攻防
morning
CVE-2025-25185 深度解析:GPT Academic 软链接解析缺陷导致任意文件读取
摘要
摘要 在处理用户上传的归档文件时,安全校验的边界一旦出现偏差,就可能引发灾难性的后果。本文将深入分析开源的学术优化工具 GPT Academic(受影响版本 ≤ 3.91)中存在的任意文件读取漏洞(CVE-2025-25185)。文章依托真实的漏洞复现截图,从核心源码的逐行拆解、恶意 Payload 的底层构造,到 Web 交互与文件读取的最终触发,完整还原了从代码审计到实战利用的全生命周期。本文...
path
full_path
dest_dir
tarobj
member
abspath
Web
tarfile
normpath
name
2026-11-12
1 阅读
约10分钟阅读
先知社区
字号:
摘要 在处理用户上传的归档文件时,安全校验的边界一旦出现偏差,就可能引发灾难性的后果。本文将深入分析开源的学术优化工具 GPT Academic(受影响版本 ≤ 3.91)中存在的任意文件读取漏洞(CVE-2025-25185)。文章依托真实的漏洞复现截图,从核心源码的逐行拆解、恶意 Payload 的底层构造,到 Web 交互与文件读取的最终触发,完整还原了从代码审计到实战利用的全生命周期。本文旨在为安全从业者提供一种关于压缩包解压场景的深度思考与防御思路。 一、 漏洞背景与攻击面概述 现代 Web 应用中,文件上传与处理是极为常见的业务需求。GPT Academic 作为一款深受科研人员喜爱的 LLM 辅助工具,提供了“上传论文/代码压缩包进行智能解析”的功能。为了支持这一功能,开发者必须实现服务端的解压逻辑。 CVE-2025-25185 的核心正是出在这个解压环节。在 Linux 与 Windows 操作系统中,除了常规的文本文件和可执行文件,还存在一种特殊的文件类型——符号链接(Symbolic Link,简称软链接)。软链接本质上是一个指向其他文件或目录的“快捷方式”。 由于项目在处理 .tar.gz 压缩包时,底层调用了 Python 的 tarfile 模块,且未对解压成员的文件属性进行安全过滤,导致攻击者可以向服务器植入一个指向系统敏感文件(如 win.ini、/etc/passwd 或 .env 等)的软链接。当 Web 服务后续通过路由访问该解压目录时,由于操作系统的底层文件系统解析机制,服务端会跟随这个软链接,将目标敏感文件的真实内容直接回显给攻击者,造成严重的信息泄露。 二、 漏洞现场:探寻深藏的“伪防御” 要彻底理解漏洞,必须回归代码。图1展示了该项目存在漏洞的核心源码,这也是我们整个代码审计工作的起点。 with tarfile.open(file_path, "r:*") as tarobj: # 清理提取路径,移除任何不安全的元素 for member in tarobj.getmembers(): member_path = os.path.normpath(member.name) full_path = os.path.join(dest_dir, member_path) full_path = os.path.abspath(full_path) if not full_path.startswith(os.path.abspath(dest_dir) + os.sep): raise Exception(f"Attempted Path Traversal in {member.name}") tarobj.extractall(path=dest_dir) logger.info(f"Successfully extracted tar archive to {dest_dir}") 2.1 逐行代码审计与“善意”的防御 在截图中的 109 到 115 行,我们能看出开发者其实是具备一定安全意识的。这段代码试图防御经典的 路径穿越漏洞(Zip-Slip): os.path.normpath(member.name):开发者遍历了压缩包内的所有成员,并试图规范化文件名,消除 ../ 这类危险字符。 full_path = os.path.abspath(full_path):计算出最终解压的绝对物理路径。 if not full_path.startswith(...):这是一个经典的防御策略。它判断解压后文件的物理路径,是否依然以预设的安全解压目录 dest_dir 开头。如果不是,就抛出异常阻断攻击。 如果攻击者试图在压缩包内放入名为 ../../../../Windows/System32/evil.txt 的文件,normpath 和 abspath 计算后,其路径就会脱离 dest_dir 的控制范围,从而被 startswith 逻辑拦截。这套针对文件名和路径的校验逻辑本身是严密且合理的。 2.2 破绽在哪?被忽视的“文件类型” 这套看似完美的防御,恰恰暴露了最大的盲区。开发者只校验了文件的“名字”,却忽略了文件的“物理属性(类型)”。 在 118 行,代码安全校验通过后,直接调用了 tarobj.extractall(path=dest_dir)。在 Python 的 tarfile 模块中,extractall 方法极为强大,它不但会解压普通文件,还会忠实地按照 Tar 归档包内的元数据,为 符号链接(Symlink) 和 硬链接(Hardlink) 创建映射。 攻击者的思路由此豁然开朗:既然无法通过命名(如 ../../)逃逸目录,那不如在安全目录内放置一个“特洛伊木马”软链接。比如,这个软链接名字就叫 hacked.txt,它的路径完全合法,能轻松通过所有的 startswith 校验;但是,这个 hacked.txt 的物理指向,却是系统深处的 C:\Windows\win.ini。当后续业务读取 hacked.txt 时,操作系统顺藤摸瓜,就把 win.ini 的内容交了出来。 这就是典型的逻辑漏洞。开发者在路径层面上了锁,却没有发现攻击者直接在屋里挖了个地道。 三、 靶场环境确认与攻击准备 在进行漏洞复现之前,必须确保靶场的版本处于“脆弱状态”。图2展示了靶场的运行环境。 页面顶端赫然写着 “GPT 学术优化 3.91”,这是存在该漏洞的核心版本。界面正常渲染,右侧展示了丰富的基础功能与函数插件区,上方有“上传文件”的选项卡。这与真实的业务场景完全吻合,确保了漏洞利用链的完整性。在这个界面之下,承载着上述漏洞代码的 Web 后端正在静默运行。 为了触发漏洞,我们需要构造一个恶意的 .tar.gz 压缩包。在常规的 Windows 环境下,普通用户权限无法直接使用 mklink 命令创建软链接,直接通过 7-Zip 等可视化压缩软件也无法直接打包软链接结构。 因此,必须从代码层面直接操作数据结构,编写专用的 PoC 生成脚本。 四、 构造“数字特洛伊木马”:Payload 深剖 图3展示了通过命令行执行 Python 脚本生成恶意压缩包的全过程。 D:\gpt_academic>python poc.py 正在生成 payload.tar.gz ... ✅ 恶意压缩包 payload.tar.gz 生成成功!可以去上传了。 看似简单的一行输出,背后却蕴含着精妙的底层逻辑。这个恶意包是如何欺骗系统的?其生成的核心原理如下: import tarfile target_file = r"C:\Windows\win.ini" link_name = "hacked.txt" with tarfile.open("payload.tar.gz", "w:gz") as tar: info = tarfile.TarInfo(link_name) # 创建一个归档成员对象 info.type = tarfile.SYMTYPE # 【核心】声明该文件为符号链接 info.linkname = target_file # 【核心
这篇文章对您有帮助吗?
订阅66必读
每日精选科技资讯,直达你的邮箱