The Wayback Machine - https://web.archive.org/web/20250522065211/https://github.com/github/codeql/pull/8004
Skip to content

Add query to detect ZipSlip #8004

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 66 commits into from
Apr 8, 2022
Merged

Add query to detect ZipSlip #8004

merged 66 commits into from
Apr 8, 2022

Conversation

ahmed-farid-dev
Copy link
Contributor

Zip Slip is a widespread critical archive extraction vulnerability, allowing attackers to write arbitrary files on the system, typically resulting in remote command execution

@ahmed-farid-dev
Copy link
Contributor Author

Hello, any update on this ?

Copy link
Contributor

@tausbn tausbn left a comment

Choose a reason for hiding this comment

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

Thank you for your submission!

I have made some comments and suggestions for improving this query and getting it into a state where it can be merged.

In addition to the various things I point out, the main thing missing at this point is a set of tests that demonstrate what the query can (and if relevant, cannot) do in its present state. I would especially like to see a test of the sanitizer.

CopyZip() {
exists(DataFlow::CallCfgNode call, DataFlow::Node pred |
call = API::moduleImport("shutil").getMember([
// these are used to copy files
Copy link
Contributor

Choose a reason for hiding this comment

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

The formatting here looks really weird. Has this been formatted using the standard autoformatter? If not, it needs to be in order to get merged, since we enforce this on all of our QL code. (To use the autoformatter, you can either invoke it via the VSCode extension, or the CodeQL CLI.)


abstract class OpenZipFile extends DataFlow::CallCfgNode { }

private class CopyZip extends CopyZipFile {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see anything in this class that makes it specific to zip files, so it's not clear to me why it should contain Zip in its name.

to prevent writing files to unexpected locations.</p>

<p>The recommended way of writing an output file from a Zip archive entry is to use
this function instead of <code>extract()</code> or <code>extractall()</code>.
Copy link
Contributor

Choose a reason for hiding this comment

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

It is not clear to me what "this function" refers to. Do you in fact mean the opposite of what you've written, that the recommended way is to call extract or extractall?


<sample src="zipslip_bad.py" />

<p>To fix this vulnerability, we need to this function <code>extractall()</code>.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
<p>To fix this vulnerability, we need to this function <code>extractall()</code>.
<p>To fix this vulnerability, we need to call the function <code>extractall()</code>.

with zf.open() as zipf:
#BAD : This could write any file on the filesystem.
for entry in zipf:
shutil.copyfileobj(entry, "/tmp/unpack/")
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
shutil.copyfileobj(entry, "/tmp/unpack/")
shutil.copyfileobj(entry, "/tmp/unpack/")

This would be a syntax error otherwise.

"move"])
.getACall() and

call.getArg(0) = pred
Copy link
Contributor

Choose a reason for hiding this comment

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

What purpose does pred serve here? It's only mentioned on this line, as far as I can see. You could equivalently just write exists(call.getArg(0)), or just remove it altogether.

abstract class OpenZipFile extends DataFlow::CallCfgNode { }

private class CopyZip extends CopyZipFile {
CopyZip() {
Copy link
Contributor

Choose a reason for hiding this comment

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

This predicate does not mention this, and so it will in fact hold for all dataflow nodes, assuming there is at least one call, somewhere in the source code, to one of the listed methods on shutil.

(This is why it's important to write tests!)

Comment on lines 27 to 31
OpenZip() {
exists(DataFlow::CallCfgNode call |
call = API::moduleImport("zipfile").getMember("ZipFile").getMember("open").getACall()
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, this characteristic predicate does not mention this, and so the set of nodes it encompasses is all the nodes in OpenZipFile. You probably want to write this = ... instead of call = ..., as I imagine you want to capture the return value of the given function.


zf = zipfile.ZipFile(filename)
with zipfile.open() as zipf:
for entry in zipf:
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
for entry in zipf:
for entry in zipf:

To make the indentation consistent.

with zf.open() as zipf:
#BAD : This could write any file on the filesystem.
for entry in zipf:
shutil.copyfileobj(entry, "/tmp/unpack/")
Copy link
Contributor

Choose a reason for hiding this comment

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

cf. my earlier comment about copyfileobj, does this code actually do what you intend it to do?

@github github deleted a comment Feb 25, 2022
@github github deleted a comment Feb 25, 2022
@ahmed-farid-dev
Copy link
Contributor Author

Hi @tausbn,
i get some trouble in running the test, can you help me pls?
zip

@ahmed-farid-dev
Copy link
Contributor Author

ahmed-farid-dev commented Mar 2, 2022

Hello @tausbn,
I removed the sanitizer because he will miss some shot

@tausbn
Copy link
Contributor

tausbn commented Mar 2, 2022

Hi @tausbn, i get some trouble in running the test, can you help me pls? zip

I'm a bit confused. What tests are you trying to run here? As far as I can tell you have not added any tests to this PR. Tests should live in the python/ql/test/experimental directory.

As for the error you're seeing above, perhaps your branch is out of date compared to the current codeql main? You could try merging in main and see if this fixes the warning about database upgrades.

@ahmed-farid-dev
Copy link
Contributor Author

@tausbn, i try but it still showing up.
py-zip-slip

@tausbn
Copy link
Contributor

tausbn commented Mar 3, 2022

@tausbn, i try but it still showing up. py-zip-slip

Hmm... It's not really clear to me why that's happening. I tried pulling down your PR branch, and running the tests through VSCode, and that built the database just fine (though the tests fail to compile, see below).

I also tried invoking codeql using the gh command line application, and that had no issue with building the database either:

$ gh codeql test run python/ql/test/experimental/query-tests/Security/CWE-022/ZipSlip.qlref 
Executing 1 tests in 1 directories.
Extracting test database in /workspaces/codeql/python/ql/test/experimental/query-tests/Security/CWE-022.
Compiling queries in /workspaces/codeql/python/ql/test/experimental/query-tests/Security/CWE-022.
--- expected
+++ actual
@@ -1,1 +1,1 @@
-
+ERROR: Could not resolve type OpenFile (/workspaces/codeql/python/ql/src/experimental/semmle/python/security/ZipSlip.qll:9,69-77)
[1/1 comp 2.4s] FAILED(COMPILATION) /workspaces/codeql/python/ql/test/experimental/query-tests/Security/CWE-022/ZipSlip.qlref
0 tests passed; 1 tests failed:
  FAILED: /workspaces/codeql/python/ql/test/experimental/query-tests/Security/CWE-022/ZipSlip.qlref

What version of the CLI are you using?

@ahmed-farid-dev
Copy link
Contributor Author

@tausbn i hope this changes will be enough

@ahmed-farid-dev
Copy link
Contributor Author

for the autoformat checks, i use codeql query format

ahmed-farid-dev and others added 9 commits April 5, 2022 12:37
- Remove use of points-to.
- Exclude sources and sinks in the standard library (to prevent test brittleness).
We need to import `tty` in order to be able to detect the standard library correctly.
Copy link
Contributor

@tausbn tausbn left a comment

Choose a reason for hiding this comment

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

I took the liberty of fixing up the issues that were preventing this PR from getting merged.

If you decide to submit any other PRs, please

  • ensure that all the tests pass and rerun them whenever you make changes, and
  • ensure that the files are autoformatted at all times.

This will greatly help lessen the amount of friction encountered when reviewing and merging your contributions.

Thank you for the contribution.

@tausbn tausbn merged commit 626770a into github:main Apr 8, 2022
@ahmed-farid-dev ahmed-farid-dev deleted the ZipSlip branch April 20, 2022 12:16
@ahmed-farid-dev
Copy link
Contributor Author

Hi @tausbn ,
pls, Can do anything about github/securitylab#538 ?

@tausbn
Copy link
Contributor

tausbn commented Apr 25, 2022

Hi @tausbn , pls, Can do anything about github/securitylab#538 ?

I'm sorry, but I don't have any further involvement in that issue.

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
HTTPS · web.archive.org
← Home