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

Ruby: Decompression Bombs #13556

Merged
merged 16 commits into from
May 16, 2024
Merged

Ruby: Decompression Bombs #13556

merged 16 commits into from
May 16, 2024

Conversation

am0o0
Copy link
Contributor

@am0o0 am0o0 commented Jun 24, 2023

This is part of All for one, one for all query submission, I'm going to submit an issue in github/securitylab for this pull request too.
I wrote two versions which V2 is using recursion by use of API graphs to find zip file sinks. I added V1 because I think it maybe have some advantage in your opinion but I prefer V2. the predicates in V2 can used in ZipSlip query too I can work on this too if you agree.( I couldn't write the recursion predicate without the initial help of @asgerf in #13431)
I added the only sanitizer that I think is available which is checking the size of each zip entry.
Also I added some instance of some really popular additional taint steps which I think it is good to be added as global steps.

@smowton
Copy link
Contributor

smowton commented Jun 24, 2023

Anyone not watching the repo in general, note this is part of a family of submissions:

#13553
#13554
#13555
#13556
#13557
#13558

@am0o0
Copy link
Contributor Author

am0o0 commented Jun 25, 2023

Anyone not watching the repo in general, note this is part of a family of submissions:

#13553 #13554 #13555 #13556 #13557 #13558

#13560 is added too

@github-actions
Copy link
Contributor

QHelp previews:

ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp

errors/warnings:

A fatal error occurred: Failed to read path ./ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql
(eventual cause: NoSuchFileException "./ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql")

Copy link

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

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

CodeQL found more than 10 potential problems in the proposed changes. Check the Files changed tab for more details.

@am0o0
Copy link
Contributor Author

am0o0 commented Jun 26, 2023

Hi, I've completed the work on this query.

@calumgrant
Copy link
Contributor

Hey @amammad, would you be able to submit these to the Security Lab bug bounty program using this template as this will help us prioritise this work, and it would also be really helpful to test the CVEs found as well.

Thank you for your submission!

@am0o0
Copy link
Contributor Author

am0o0 commented Jul 11, 2023

@calumgrant I'll submit related issues in GH security lab in this week.

@github-actions
Copy link
Contributor

QHelp previews:

ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp

errors/warnings:

/home/runner/work/codeql/codeql/ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp:15:4: element "p" not allowed here; expected the element end-tag or element "example", "fragment", "howToAddress", "hr", "include", "overview", "recommendation", "references", "section" or "semmleNotes"
/home/runner/work/codeql/codeql/ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp:16:10: element "example" not allowed here; expected the element end-tag, text or element "a", "b", "code", "em", "i", "img", "strong", "sub", "sup" or "tt"
/home/runner/work/codeql/codeql/ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp:21:13: element "references" not allowed here; expected the element end-tag, text or element "a", "b", "code", "em", "i", "img", "strong", "sub", "sup" or "tt"
/home/runner/work/codeql/codeql/ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp:32:3: The element type "p" must be terminated by the matching end-tag "</p>".
A fatal error occurred: 1 qhelp files could not be processed.

@ghsecuritylab ghsecuritylab marked this pull request as draft July 31, 2023 16:03
Comment on lines +127 to +139
API::Node rubyZipNode(API::Node base) {
result = base
or
result = rubyZipNode(base).getMethod(_)
or
result = rubyZipNode(base).getReturn()
or
result = rubyZipNode(base).getParameter(_)
or
result = rubyZipNode(base).getAnElement()
or
result = rubyZipNode(base).getBlock()
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi, I can't use a predicate with a better performance like the following here:

API::Node rubyZipNode() {
    result = zipFile()
    or
    result = rubyZipNode().getMethod(_)
    or
    result = rubyZipNode().getReturn()
    or
    result = rubyZipNode().getParameter(_)
    or
    result = rubyZipNode().getAnElement()
    or
    result = rubyZipNode().getBlock()
  }

because lines 164 and 165 won't work for this then.

@ghsecuritylab ghsecuritylab marked this pull request as ready for review October 18, 2023 14:33
@github-actions
Copy link
Contributor

QHelp previews:

ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp

errors/warnings:

/home/runner/work/codeql/codeql/ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp:15:4: element "p" not allowed here; expected the element end-tag or element "example", "fragment", "howToAddress", "hr", "include", "overview", "recommendation", "references", "section" or "semmleNotes"
/home/runner/work/codeql/codeql/ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp:16:10: element "example" not allowed here; expected the element end-tag, text or element "a", "b", "code", "em", "i", "img", "strong", "sub", "sup" or "tt"
/home/runner/work/codeql/codeql/ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp:21:13: element "references" not allowed here; expected the element end-tag, text or element "a", "b", "code", "em", "i", "img", "strong", "sub", "sup" or "tt"
/home/runner/work/codeql/codeql/ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp:32:3: The element type "p" must be terminated by the matching end-tag "</p>".
A fatal error occurred: 1 qhelp files could not be processed.

Copy link
Contributor

@alexrford alexrford left a comment

Choose a reason for hiding this comment

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

Hi, I've run an initial review of this. Some of the feedback here may overlap with comments on the versions of this query for other languages.


override DataFlow::Node sink() {
result = this.getMethod(["extract", "read"]).getReturn().asSource() and
not exists(this.getMethod("size").getReturn().getMethod(">").getParameter(0))
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably be using DataFlow::OperationNode and/or Ast::RelationalOperation to detect other inequality tests (e.g. >, <, <=, >=) here.

I'm also not sure that restricting this to just cases where entry.size is the greater operand is desirable. e.g. the following both function as sanitizers:

if entry.size > limit
  raise "exceeds limit"
else
  entry.extract
end
if entry.size < limit
  entry.extract
else
  raise "exceeds limit"
end

@am0o0
Copy link
Contributor Author

am0o0 commented Mar 10, 2024

Hi @alexrford
Is it possible for you to review this PR before 25/3?
I have two weeks of forced vacation from 25/03 so I can focus on finishing this and other codeql PRs.

@alexrford alexrford self-requested a review May 16, 2024 12:52
Copy link
Contributor

@alexrford alexrford left a comment

Choose a reason for hiding this comment

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

Sorry for the delay, approved.

Copy link
Contributor

github-actions bot commented May 16, 2024

QHelp previews:

ruby/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp

User-controlled file decompression

Extracting Compressed files with any compression algorithm like gzip can cause to denial of service attacks.

Attackers can compress a huge file which created by repeated similiar byte and convert it to a small compressed file.

Recommendation

When you want to decompress a user-provided compressed file you must be careful about the decompression ratio or read these files within a loop byte by byte to be able to manage the decompressed size in each cycle of the loop.

Please read official RubyZip Documentation here

Example

Rubyzip: According to official Documentation

MAX_FILE_SIZE = 10 * 1024**2 # 10MiB
MAX_FILES = 100
Zip::File.open('foo.zip') do |zip_file|
  num_files = 0
  zip_file.each do |entry|
    num_files += 1 if entry.file?
    raise 'Too many extracted files' if num_files > MAX_FILES
    raise 'File too large when extracted' if entry.size > MAX_FILE_SIZE
    entry.extract
  end
end
# "Note that if you use the lower level Zip::InputStream interface, rubyzip does not check the entry sizes"
zip_stream = Zip::InputStream.new(File.open('file.zip'))
while entry = zip_stream.get_next_entry
  # All required operations on `entry` go here.
end

References

Copy link
Contributor

@alexrford alexrford left a comment

Choose a reason for hiding this comment

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

Just a couple of suggestions to make CI pass.

Comment on lines 14 to 15
</recommendation>
<p>Please read official RubyZip Documentation <a href="https://github.com/rubyzip/rubyzip/#size-validation">here</a></p>
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
</recommendation>
<p>Please read official RubyZip Documentation <a href="https://github.com/rubyzip/rubyzip/#size-validation">here</a></p>
<p>Please read official RubyZip Documentation <a href="https://github.com/rubyzip/rubyzip/#size-validation">here</a></p>
</recommendation>

This should fix the qhelp check error.

* @problem.severity error
* @security-severity 7.8
* @precision high
* @id rb/user-controlled-file-decompression
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
* @id rb/user-controlled-file-decompression
* @id rb/user-controlled-data-decompression

For consistency with JS and to address the duplicate query ID check.

@@ -0,0 +1,114 @@
edges
Copy link
Contributor

Choose a reason for hiding this comment

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

This .expected file looks like it needs to be regenerated to account for a change in the edges relation format.

@am0o0
Copy link
Contributor Author

am0o0 commented May 16, 2024

Sorry for the delay, approved.

Thank you a lot for approving this PR and developing and improving the CodeQL every day :)


import ruby
private import codeql.ruby.Concepts
private import codeql.ruby.DataFlow

Check warning

Code scanning / CodeQL

Redundant import Warning

Redundant import, the module is already imported inside
DecompressionBombs
.
@alexrford alexrford merged commit 19e2af8 into github:main May 16, 2024
21 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.

None yet

5 participants