-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Conversation
|
Hello, any update on this ? |
There was a problem hiding this 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 |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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>. |
There was a problem hiding this comment.
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>. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| <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/") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| shutil.copyfileobj(entry, "/tmp/unpack/") | |
| shutil.copyfileobj(entry, "/tmp/unpack/") |
This would be a syntax error otherwise.
| "move"]) | ||
| .getACall() and | ||
|
|
||
| call.getArg(0) = pred |
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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!)
| OpenZip() { | ||
| exists(DataFlow::CallCfgNode call | | ||
| call = API::moduleImport("zipfile").getMember("ZipFile").getMember("open").getACall() | ||
| ) | ||
| } |
There was a problem hiding this comment.
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: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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/") |
There was a problem hiding this comment.
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?
|
Hi @tausbn, |
|
Hello @tausbn, |
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 As for the error you're seeing above, perhaps your branch is out of date compared to the current |
|
@tausbn, i try but it still showing up. |
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 What version of the CLI are you using? |
|
@tausbn i hope this changes will be enough |
|
for the autoformat checks, i use |
- 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.
There was a problem hiding this 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.
|
Hi @tausbn , |
I'm sorry, but I don't have any further involvement in that issue. |


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