The ArchiveReader.extractContents() function used by cctl image load and container image load performs no pathname validation before extracting an archive member. This means that a carelessly or maliciously constructed archive can extract a file into any user-writable location on the system using relative pathnames.
The code in question is: https://github.com/apple/containerization/blob/main/Sources/ContainerizationArchive/Reader.swift#L180.
/// Extracts the contents of an archive to the provided directory.
/// Currently only handles regular files and directories present in the archive.
public func extractContents(to directory: URL) throws {
let fm = FileManager.default
var foundEntry = false
for (entry, data) in self {
guard let p = entry.path else { continue }
foundEntry = true
let type = entry.fileType
let target = directory.appending(path: p)
switch type {
case .regular:
try data.write(to: target, options: .atomic)
case .directory:
try fm.createDirectory(at: target, withIntermediateDirectories: true)
case .symbolicLink:
guard let symlinkTarget = entry.symlinkTarget, let linkTargetURL = URL(string: symlinkTarget, relativeTo: target) else {
continue
}
try fm.createSymbolicLink(at: target, withDestinationURL: linkTargetURL)
default:
continue
}
chmod(target.path(), entry.permissions)
if let owner = entry.owner, let group = entry.group {
chown(target.path(), owner, group)
}
}
guard foundEntry else {
throw ArchiveError.failedToExtractArchive("no entries found in archive")
}
}
Sample script make-evil-tar.py:
#! /usr/bin/env python3
import...
0.8.00.21.0Exploitability
AV:LAC:LAT:NPR:LUI:NVulnerable System
VC:LVI:LVA:NSubsequent System
SC:NSI:NSA:N1.9/CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:P