Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift: Trivial changes to swift/unsafe-unpacking #15607

Merged
merged 4 commits into from
Feb 13, 2024

Conversation

geoffw0
Copy link
Contributor

@geoffw0 geoffw0 commented Feb 13, 2024

Trivial changes to the new swift/unsafe-unpacking query:

  • describe it as "experimental" in the change note.
  • rename an example file to have consistent casing with the other example.
  • move both CWE-020 queries tests to be in a common parent directory (as we do for other CWEs with more than one query).
  • fix for a merge conflict with the "provenance" change, that was causing the test to fail.

@geoffw0 geoffw0 added the Swift label Feb 13, 2024
@geoffw0 geoffw0 requested a review from a team as a code owner February 13, 2024 18:06
Copy link
Contributor

QHelp previews:

swift/ql/src/experimental/Security/CWE-022/UnsafeUnpack.qhelp

Arbitrary file write during a zip extraction from a user controlled source

Unpacking files from a malicious zip without properly validating that the destination file path is within the destination directory, or allowing symlinks to point to files outside the extraction directory, allows an attacker to extract files to arbitrary locations outside the extraction directory. This helps overwrite sensitive user data and, in some cases, can lead to code execution if an attacker overwrites an application's shared object file.

Recommendation

Consider using a safer module, such as: ZIPArchive

Example

The following examples unpacks a remote zip using `Zip.unzipFile()` which is vulnerable to path traversal.

import Foundation
import Zip


func unzipFile(at sourcePath: String, to destinationPath: String) {
    do {
        let remoteURL = URL(string: "https://example.com/")!

        let source  = URL(fileURLWithPath: sourcePath)
        let destination = URL(fileURLWithPath: destinationPath)

        // Malicious zip is downloaded 
        try Data(contentsOf: remoteURL).write(to: source)

        let fileManager = FileManager()
        // Malicious zip is unpacked
        try Zip.unzipFile(source, destination: destination, overwrite: true, password: nil)
        } catch {
    }
}

func main() {
    let sourcePath = "/sourcePath" 
    let destinationPath = "/destinationPath" 
    unzipFile(at: sourcePath, to: destinationPath)
}

main()

The following examples unpacks a remote zip using `fileManager.unzipItem()` which is vulnerable to symlink path traversal.

import Foundation
import ZIPFoundation


func unzipFile(at sourcePath: String, to destinationPath: String) {
    do {
        let remoteURL = URL(string: "https://example.com/")!

        let source  = URL(fileURLWithPath: sourcePath)
        let destination = URL(fileURLWithPath: destinationPath)

        // Malicious zip is downloaded 
        try Data(contentsOf: remoteURL).write(to: source)

        let fileManager = FileManager()
        // Malicious zip is unpacked
        try fileManager.unzipItem(at:source, to: destination)
        } catch {
    }
}

func main() {
    let sourcePath = "/sourcePath" 
    let destinationPath = "/destinationPath" 
    unzipFile(at: sourcePath, to: destinationPath)
}

main()

Consider using a safer module, such as: ZIPArchive

import Foundation
import ZipArchive

func unzipFile(at sourcePath: String, to destinationPath: String) {
    do {
        let remoteURL = URL(string: "https://example.com/")!

        let source  = URL(fileURLWithPath: sourcePath)

        // Malicious zip is downloaded 
        try Data(contentsOf: remoteURL).write(to: source)

        // ZipArchive is safe
        try SSZipArchive.unzipFile(atPath: sourcePath, toDestination: destinationPath, delegate: self)
        } catch {
    }
}

func main() {
    let sourcePath = "/sourcePath" 
    let destinationPath = "/destinationPath" 
    unzipFile(at: sourcePath, to: destinationPath)
}

main()

References

Copy link
Contributor

@MathiasVP MathiasVP left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@geoffw0 geoffw0 merged commit 0d6c141 into github:main Feb 13, 2024
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants