Skip to content

Swift: Add Unsafe Unpacking Query (CWE-022) #14888

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

Merged
merged 10 commits into from
Feb 13, 2024

Conversation

maikypedia
Copy link
Contributor

This pull request adds a query for Unsafe Unpacking covering Zip and ZIPFoundation.

Looking forward to your suggestions.

@maikypedia maikypedia requested a review from a team as a code owner November 23, 2023 11:51
@maikypedia maikypedia changed the title Add Unsafe Unpacking Query (CWE-022) Swift: Add Unsafe Unpacking Query (CWE-022) Nov 23, 2023
@ghsecuritylab ghsecuritylab marked this pull request as draft November 23, 2023 13:48
@ghsecuritylab
Copy link
Collaborator

Hello maikypedia 👋
You have submitted this pull request as a bug bounty report in the github/securitylab repository and therefore this pull request has been put into draft state to give time for the GitHub Security Lab to assess the PR. When GitHub Security Lab has finished assessing your pull request, it will be marked automatically as Ready for review. Until then, please don't change the draft state.

In the meantime, feel free to make changes to the pull request. If you'd like to maximize payout for your this and future submissions, here are a few general guidelines, that we might take into consideration when reviewing a submission.

  • the submission models widely-used frameworks/libraries
  • the vulnerability modeled in the submission is impactful
  • the submission finds new true positive vulnerabilities
  • the submission finds very few false positives
  • code in the submission is easy to read and will be easy to maintain
  • documentation is written clearly, highlighting the impact of the issue it finds and is written without grammatical or other errors. The code samples clearly show the vulnerability
  • the submission includes tests, change note etc.

Please note that these are guidelines, not rules. Since we have a lot of different types of submissions, the guidelines might vary for each submission.

Happy hacking!

@geoffw0
Copy link
Contributor

geoffw0 commented Nov 23, 2023

Hi @maikypedia,

Thank you for this contribution. The QL appears to be to a high standard and I'm interested to see what this query can find. After the Security Lab team have taken a look I'll be happy to give a more detailed review from the Swift / QL perspective. Feel free to @mention me if you have any questions before then.

Copy link
Contributor

github-actions bot commented Jan 25, 2024

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

@ghsecuritylab ghsecuritylab marked this pull request as ready for review January 25, 2024 10:16
Copy link
Contributor

@geoffw0 geoffw0 left a comment

Choose a reason for hiding this comment

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

Hi, sorry for the long wait. The query looks great, I've suggested a few minor fixes and changes.

maikypedia and others added 5 commits February 7, 2024 14:26
Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
@geoffw0
Copy link
Contributor

geoffw0 commented Feb 7, 2024

Thanks for addressing the comments.

CI has noticed that we're missing a change note. This will be a new file in cpp\ql\src\change-notes with contents along the lines of:

---
category: newQuery
---
* Added a new query, `swift/unsafe-unpacking`, that detects unpacking user controlled zips without validating the destination file path is within the destination directory.

Copy link
Contributor

@geoffw0 geoffw0 left a comment

Choose a reason for hiding this comment

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

Great, I think this is ready to merge.

Thank you for your contribution! ✨

@geoffw0
Copy link
Contributor

geoffw0 commented Feb 8, 2024

@maikypedia you should be able to hit "Merge pull request" now if you're also satisfied that this is finished.

@maikypedia
Copy link
Contributor Author

@maikypedia you should be able to hit "Merge pull request" now if you're also satisfied that this is finished.

image

I can't 😅

@geoffw0
Copy link
Contributor

geoffw0 commented Feb 13, 2024

Ah, sorry, I didn't know that was a thing. Merging now.

@geoffw0 geoffw0 merged commit fd1314b into github:main Feb 13, 2024
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.

3 participants