7-Zip 最近被發現兩個安全漏洞:CVE-2025-11001 及 CVE-2025-11002,問題源於 7-Zip 解壓縮時對符號連結(Symbolic Link)與目錄穿越(Directory Traversal)的處理邏輯不夠周全,導致攻擊者可在 ZIP 檔刻意放入特殊的符號連結以「繞出」預期目錄,將惡意檔案覆蓋或寫入到系統敏感位置。一個可行的攻擊途徑是攻擊者設法將惡意 ZIP 檔送到使用者手上並誘騙其進行解壓縮,藉由漏洞將系統服務或使用者常用執行檔換成植入惡意程式的版本,一但加料版被執行即可完成攻擊。
延伸閱讀:

7-Zip 的最新版本 25.01已修正這個兩個漏洞,建議大家盡快更新。
(題外話:以 7-Zip 的輕巧穩定,執行速度快,功能又完整,Windows 真該把它收為內建工具並自動更新。)

檢查版本理論上用檔案總管就可以了。

但為確保修補作業沒有遺漏,我決定寫個 PowerShell 腳本掃瞄資料夾,找出所有 7z.exe/7z.dll 並檢查版本,確保都有更新到最新版。

param (
    [Parameter(Mandatory = $true)]
    [string]$Path,
    [string]$CsvPath,
    [string[]]$Exclude = @()
)

function CheckVersion($filePath) {
    $version = '?'
    try {
        $version = (Get-Item $filePath).VersionInfo.ProductVersion
        $majorVersion = [int]::Parse($version.Split('.')[0])
        $passed = $majorVersion -ge 25
        $status = if ($passed) { "PASS" } else { "FAIL" }
    }
    catch {
        $status = "ERROR"
    }
    return [PSCustomObject]@{
        Path    = $filePath
        Version = $version
        Status  = $status
    }
}
function ShowResult($result) {
    $color = if ($result.Status -eq 'PASS') { 'Green' } elseif ($result.Status -eq 'FAIL') { 'Red' } else { 'Cyan' }
    Write-Host "$($result.Status)`t$($result.Version)`t$($result.Path)" -ForegroundColor $color
}

$gciErrors = $null

# -File to ensure we only get files, not directories
# -Force to include hidden/system directories/files
# -ErrorAction SilentlyContinue to suppress errors (e.g., access denied)
# -ErrorVariable gciErrors to capture any errors for later reporting
$results = @() 

if ($Path.EndsWith('.csv')) {
    $csvPaths = @()
    try {
        $csvPaths = Import-Csv -Path $Path | ForEach-Object { $_.Path } | Where-Object { Test-Path $_ }
    }
    catch {
        Write-Host "Error reading CSV file: $_" -ForegroundColor Red
        exit 1
    }
    Write-Host "Verifying paths from [$Path]..." -ForegroundColor Yellow
    foreach ($csvPath in $csvPaths) {
        if (Test-Path $csvPath) {
            $result = CheckVersion -filePath $csvPath
            ShowResult -result $result
            $results += $result
        }
        else {
            $result = ([PSCustomObject]@{
                    Path    = $csvPath
                    Version = '?'
                    Status  = '404'
                })
            ShowResult -result $result
            $results += $result
        }
    }
    $CsvPath = $Path
    Write-Host "`nUpdating results to [$CsvPath]..." -ForegroundColor Yellow
    $results | Export-Csv -Path $CsvPath -NoTypeInformation -Encoding UTF8
}
else {
    $sw = [System.Diagnostics.Stopwatch]::StartNew()
    Write-Host "Scanning path [$Path] for 7z.exe and 7z.dll files..." -ForegroundColor Yellow
    $sw.Start()
    Get-ChildItem -Path $Path -Recurse -Directory -Force -ErrorAction SilentlyContinue -ErrorVariable +gciErrors | 
    Where-Object {
        $excludeMatch = $false
        foreach ($excl in $Exclude) {
            if ($_.Name -ieq $excl -or $_.FullName -like "*\$excl\*") {
                $excludeMatch = $true
                break
            }
        }
        return -not $excludeMatch
    } |
    ForEach-Object {
        Write-Progress -Activity "Scanning directories..." -Status "Processing: $($_.FullName)" 
        Get-ChildItem -Path $_.FullName -Filter '7z.*' -File -Force -ErrorAction SilentlyContinue -ErrorVariable +gciErrors | 
        Where-Object { $_.Name -ieq '7z.exe' -or $_.Name -like '7z.dll' } |
        ForEach-Object {
            $result = CheckVersion -filePath $_.FullName
            ShowResult -result $result
            $results += $result
        }
    }
    $sw.Stop()
    Write-Host "`nScan completed in $($sw.Elapsed.TotalSeconds.ToString('n0')) seconds." -ForegroundColor Yellow
    # Generate default output CSV path
    if (-not $CsvPath) {
        $CsvPath = Join-Path -Path (Get-Location) -ChildPath "7zip_Scan_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
    }
    Write-Host "`nExporting results to [$CsvPath]..." -ForegroundColor Yellow
    $results | Export-Csv -Path $CsvPath -NoTypeInformation -Encoding UTF8

    if ($gciErrors) {
        $displayErrors = Read-Host "`n$($gciErrors.Count) IO Errors, display? (Y/N)"
        if ($displayErrors -ieq 'Y') {
            $sb = New-Object -TypeName System.Text.StringBuilder
            foreach ($err in $gciErrors) {
                $sb.AppendLine($err.Exception.Message) | Out-Null
            }
            $tempPath = [System.IO.Path]::GetTempFileName() + ".txt"
            $sb.ToString() | Out-File -FilePath $tempPath -Encoding UTF8
            Start-Process -FilePath $tempPath
        }
    }
}

使用方法很簡單 Atk-Scan7zipVersion.ps1 D:\ 即可找出 D 槽所有的 7z.exe 及 7z.dll 的版本,大於 25.X 的顯示綠色,否則紅色 (無法判斷版號顯示灰色,理論上不會發生),並將結果存成 CSV。CSV 檔會依日期時間自動命名,或者也可自行指定,例如:Atk-Scan7zipVersion.ps1 D:\ -CsvPath E:\results.csv。(若有確定不需掃瞄的目錄可使用 -Exclude @('Log', 'Logs') 略過節省時間)

掃瞄時建議使用管理者權限,但實務上仍可能有些系統目錄會無法存取或找不到路徑,這類存取錯誤訊息會另存暫時目錄,若有需要可以查看。

如圖所示,掃瞄一次可能耗時數分鐘,掃瞄結果會存成 CSV 方便後續修補及複核版本是否更新完成。

如要複核版本是否更新可帶入 CSV 路徑,腳本將直接依據清單上的路徑逐一檢查,並將結果更新回 CSV 檔,如此可省下重新掃瞄的時間,在幾秒內完成,。

至於修補原則,實際掃瞄會發現很多軟體都依賴 7z.exe 解壓縮,例如範例中的 Chocolatey、Visual Studio Xamarin 擴充套件... 等,這類 7z.exe 解壓對象多侷限應用程式自身的套件、更新檔等,不會被用來解壓其他檔案。由於這次的攻擊需使用者互動(如開啟特定惡意 ZIP 檔)才能完成,故風險較高的是使用者日常使用的 7-Zip 程式,至於這類軟體自帶的 7z 程式或程式庫,要被拿來作惡不是那麼容易(BUT,資安有張無敵鬼牌:萬一萬一又萬一),加上強制置換軟體所屬檔案可能會有副作用,要不要也都更新?就留給大家自行拿捏了。

【同場加映】簡單整理 7-Zip 相關 dll 的用途:

  • 7zr.dll:7zr 對應的是 Reduced (精簡版) 7-Zip,通常與 7zr.exe 搭配,只支援 7z 基本格式與核心 LZMA/LZMA2 編解碼(不含 bzip2),適合嚴格限制檔案大小且只需處理 7z, xz, lzma, split 格式的場合。參考
  • 7za.dll:對應的是 Standalone/7za.exe 的動態程式庫,只支援 .7z,不提供 ZIP, RAR, CAB 等格式。參考 另外有不需要額外 .dll 的 7za.exe 執行檔,若只需要處理 .7z,部署一個檔案即可。參考
  • 7z.dll:完整 7-Zip/SDK 的主要編解碼集合,GUI 與許多第三方程式會直接載入 7z.dll 以取得完整格式支援。
  • 7zxa.dll/7zxr.dll:只需要解壓縮 .7z 的話可用。

一般來說,如要在 .NET 或其他語言引用 7-Zip 功能,用 7z.dll 可以獲取完整格式與 AES 加密等能力,並有現成封裝元件使用較方便;只有對部署體積很嚴格時,才退而選擇 7za/7zr 的精簡組合 。

Discusses 7-Zip vulnerabilities and shares a PowerShell script to scan, verify, and update 7z.exe/7z.dll versions for enhanced security.


Comments

Be the first to post a comment

Post a comment