Merge pull request #13556 from am0o0/amammad-ruby-bombs

Ruby: Decompression Bombs
This commit is contained in:
Alex Ford
2024-05-16 16:23:02 +01:00
committed by GitHub
9 changed files with 530 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Extracting Compressed files with any compression algorithm like gzip can cause to denial of service attacks.</p>
<p>Attackers can compress a huge file which created by repeated similiar byte and convert it to a small compressed file.</p>
</overview>
<recommendation>
<p>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.</p>
<p>Please read official RubyZip Documentation <a href="https://github.com/rubyzip/rubyzip/#size-validation">here</a></p>
</recommendation>
<example>
<p>Rubyzip: According to <a href="https://github.com/rubyzip/rubyzip/#reading-a-zip-file">official</a> Documentation</p>
<sample src="example_good.rb" />
<sample src="example_bad.rb" />
</example>
<references>
<li>
<a href="https://www.cvedetails.com/cve/CVE-2022-3759/">CVE-2023-22898</a>
<a href="https://gitlab.com/gitlab-org/gitlab/-/issues/379633">Gitlab issue</a>
</li>
<li>
<a href="https://www.bamsoftware.com/hacks/zipbomb/">A great research to gain more impact by this kind of attack</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,69 @@
/**
* @name User-controlled file decompression
* @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
* @kind path-problem
* @problem.severity error
* @security-severity 7.8
* @precision high
* @id rb/user-controlled-data-decompression
* @tags security
* experimental
* external/cwe/cwe-409
*/
import ruby
private import codeql.ruby.Concepts
private import codeql.ruby.DataFlow
private import codeql.ruby.TaintTracking
import DecompressionBombs
/**
* A call to `IO.copy_stream`
*/
class IoCopyStream extends DataFlow::CallNode {
IoCopyStream() { this = API::getTopLevelMember("IO").getAMethodCall("copy_stream") }
DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
}
module BombsConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) { sink instanceof DecompressionBomb::Sink }
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(DecompressionBomb::AdditionalTaintStep ats).isAdditionalTaintStep(nodeFrom, nodeTo)
or
exists(API::Node n | n = API::getTopLevelMember("File").getMethod("open") |
nodeFrom = n.getParameter(0).asSink() and
nodeTo = n.getReturn().asSource()
)
or
nodeFrom = nodeTo.(File::FileOpen).getAPathArgument()
or
exists(API::Node n | n = API::getTopLevelMember("StringIO").getMethod("new") |
nodeFrom = n.getParameter(0).asSink() and
nodeTo = n.getReturn().asSource()
)
or
nodeFrom = nodeTo.(IoCopyStream).getAPathArgument()
or
// following can be a global additional step
exists(DataFlow::CallNode cn |
cn.getMethodName() = "open" and
cn.getReceiver().getExprNode().getExpr() instanceof Ast::SelfVariableAccess
|
nodeFrom = cn.getArgument(0) and
nodeTo = cn
)
}
}
module Bombs = TaintTracking::Global<BombsConfig>;
import Bombs::PathGraph
from Bombs::PathNode source, Bombs::PathNode sink
where Bombs::flowPath(source, sink)
select sink.getNode(), source, sink, "This file Decompression depends on a $@.", source.getNode(),
"potentially untrusted source"

View File

@@ -0,0 +1,215 @@
import codeql.ruby.AST
import codeql.ruby.frameworks.Files
import codeql.ruby.ApiGraphs
import codeql.ruby.DataFlow
import codeql.ruby.dataflow.RemoteFlowSources
module DecompressionBomb {
/**
* A abstract class responsible for extending new decompression sinks
*
* can be a path, stream of compressed data,
* or a call to function that use pipe
*/
abstract class Sink extends DataFlow::Node { }
/**
* The additional taint steps that need for creating taint tracking or dataflow.
*/
abstract class AdditionalTaintStep extends string {
AdditionalTaintStep() { this = "AdditionalTaintStep" }
/**
* Holds if there is a additional taint step between pred and succ.
*/
abstract predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ);
}
}
module Zlib {
/**
* Gets a node of `Zlib::GzipReader` member
*
* Note that if you use the lower level Zip::InputStream interface, rubyzip does not check the entry sizes.
*/
private API::Node gzipReaderInstance() {
result = API::getTopLevelMember("Zlib").getMember("GzipReader")
}
/**
* A return values of following methods
* `Zlib::GzipReader.open`
* `Zlib::GzipReader.zcat`
* `Zlib::GzipReader.new`
*/
class DecompressionBombSink extends DecompressionBomb::Sink {
DecompressionBombSink() {
this = gzipReaderInstance().getMethod(["open", "new", "zcat"]).getReturn().asSource()
}
}
/**
* The additional taint steps that need for creating taint tracking or dataflow for `Zlib`.
*/
class AdditionalTaintStep extends DecompressionBomb::AdditionalTaintStep {
AdditionalTaintStep() { this = "AdditionalTaintStep" }
override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(API::Node openOrNewOrZcat |
openOrNewOrZcat = gzipReaderInstance().getMethod(["open", "new", "zcat"])
|
nodeFrom = openOrNewOrZcat.getParameter(0).asSink() and
nodeTo = openOrNewOrZcat.getReturn().asSource()
)
}
}
}
module ZipInputStream {
/**
* Gets a node of `Zip::InputStream` member
*
* Note that if you use the lower level Zip::InputStream interface, rubyZip does not check the entry sizes.
*/
private API::Node zipInputStream() {
result = API::getTopLevelMember("Zip").getMember("InputStream")
}
/**
* The methods
* `Zip::InputStream.read`
* `Zip::InputStream.extract`
*
* as source of decompression bombs, they need an additional taint step for a dataflow or taint tracking query
*/
class DecompressionBombSink extends DecompressionBomb::Sink {
DecompressionBombSink() {
this = zipInputStream().getMethod(["open", "new"]).getReturn().asSource()
}
}
/**
* The additional taint steps that need for creating taint tracking or dataflow for `Zip`.
*/
class AdditionalTaintStep extends DecompressionBomb::AdditionalTaintStep {
AdditionalTaintStep() { this = "AdditionalTaintStep" }
override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(API::Node openOrNew | openOrNew = zipInputStream().getMethod(["open", "new"]) |
nodeFrom = openOrNew.getParameter(0).asSink() and
nodeTo = openOrNew.getReturn().asSource()
)
}
}
}
module ZipFile {
/**
* Gets a node of `Zip::File` member
*/
API::Node zipFile() { result = API::getTopLevelMember("Zip").getMember("File") }
/**
* Gets nodes that have a `base` at the beginning
*/
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()
}
/**
* The return values of following methods
* `ZipIO.read`
* `ZipEntry.extract`
* A sanitizer exists inside the nodes which have `entry.size > someOBJ`
*/
class DecompressionBombSink extends DecompressionBomb::Sink {
DecompressionBombSink() {
exists(API::Node rubyZip | rubyZip = rubyZipNode(zipFile()) |
this = rubyZip.getMethod(["extract", "read"]).getReturn().asSource() and
not exists(
rubyZip.getMethod("size").getReturn().getMethod([">", " <", "<=", " >="]).getParameter(0)
)
)
}
}
/**
* The additional taint steps that need for creating taint tracking or dataflow for `Zip::File`.
*/
class AdditionalTaintStep extends DecompressionBomb::AdditionalTaintStep {
AdditionalTaintStep() { this = "AdditionalTaintStep" }
override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(API::Node zipFile | zipFile = zipFile().getMethod("open") |
nodeFrom = zipFile.getParameter(0).asSink() and
nodeTo = rubyZipNode(zipFile).getMethod(["extract", "read"]).getReturn().asSource()
)
}
}
predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(API::Node zipFile | zipFile = zipFile().getMethod("open") |
nodeFrom = zipFile.getParameter(0).asSink() and
nodeTo = rubyZipNode(zipFile).getMethod(["extract", "read"]).getReturn().asSource()
)
}
// /**
// * The additional taint steps that need for creating taint tracking or dataflow for `Zip::File`.
// */
// class AdditionalTaintStep1 extends DecompressionBomb::AdditionalTaintStep {
// AdditionalTaintStep1() { this = "AdditionalTaintStep" }
// override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// exists(API::Node zipFile | zipFile = zipFile().getMethod("open") |
// nodeFrom = zipFile.getParameter(0).asSink() and
// nodeTo = zipFile.asSource()
// )
// }
// }
// API::Node rubyZipNode2() {
// result = zipFile().getMethod("open")
// or
// result = rubyZipNode2().getMethod(_)
// or
// result = rubyZipNode2().getReturn()
// or
// result = rubyZipNode2().getParameter(_)
// or
// result = rubyZipNode2().getAnElement()
// or
// result = rubyZipNode2().getBlock()
// }
// /**
// * The additional taint steps that need for creating taint tracking or dataflow for `Zip::File`.
// */
// class AdditionalTaintStep2 extends DecompressionBomb::AdditionalTaintStep {
// AdditionalTaintStep2() { this = "AdditionalTaintStep" }
// override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// exists(API::Node zipFileOpen | zipFileOpen = rubyZipNode2() |
// nodeFrom = zipFileOpen.getReturn().asSource() and
// nodeTo = zipFileOpen.getMethod(["extract", "read"]).getReturn().asSource()
// )
// }
// }
// /**
// * The additional taint steps that need for creating taint tracking or dataflow for `Zip::File`.
// */
// class AdditionalTaintStep3 extends DecompressionBomb::AdditionalTaintStep {
// AdditionalTaintStep3() { this = "AdditionalTaintStep" }
// override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// exists(API::Node zipFileOpen | zipFileOpen = rubyZipNode2() |
// nodeFrom = zipFileOpen.asCall() and
// nodeTo = zipFileOpen.getMethod(["extract", "read"]).getReturn().asSource()
// )
// }
// }
}

View File

@@ -0,0 +1,5 @@
# "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

View File

@@ -0,0 +1,11 @@
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

View File

@@ -0,0 +1,114 @@
edges
| gzipBombs.rb:4:3:4:11 | gzip_path | gzipBombs.rb:6:25:6:33 | gzip_path | provenance | |
| gzipBombs.rb:4:15:4:20 | call to params | gzipBombs.rb:4:15:4:27 | ...[...] | provenance | |
| gzipBombs.rb:4:15:4:27 | ...[...] | gzipBombs.rb:4:3:4:11 | gzip_path | provenance | |
| gzipBombs.rb:6:25:6:33 | gzip_path | gzipBombs.rb:6:3:6:34 | call to open | provenance | |
| gzipBombs.rb:6:25:6:33 | gzip_path | gzipBombs.rb:7:25:7:33 | gzip_path | provenance | |
| gzipBombs.rb:7:25:7:33 | gzip_path | gzipBombs.rb:7:3:9:5 | call to open | provenance | |
| gzipBombs.rb:7:25:7:33 | gzip_path | gzipBombs.rb:10:25:10:33 | gzip_path | provenance | |
| gzipBombs.rb:10:25:10:33 | gzip_path | gzipBombs.rb:10:3:14:5 | call to open | provenance | |
| gzipBombs.rb:10:25:10:33 | gzip_path | gzipBombs.rb:15:44:15:52 | gzip_path | provenance | |
| gzipBombs.rb:15:44:15:52 | gzip_path | gzipBombs.rb:15:22:15:53 | call to open | provenance | |
| gzipBombs.rb:15:44:15:52 | gzip_path | gzipBombs.rb:20:34:20:42 | gzip_path | provenance | |
| gzipBombs.rb:20:24:20:49 | call to open | gzipBombs.rb:20:3:20:50 | call to new | provenance | |
| gzipBombs.rb:20:34:20:42 | gzip_path | gzipBombs.rb:20:24:20:49 | call to open | provenance | |
| gzipBombs.rb:20:34:20:42 | gzip_path | gzipBombs.rb:21:34:21:42 | gzip_path | provenance | |
| gzipBombs.rb:21:24:21:49 | call to open | gzipBombs.rb:21:3:21:50 | call to new | provenance | |
| gzipBombs.rb:21:34:21:42 | gzip_path | gzipBombs.rb:21:24:21:49 | call to open | provenance | |
| gzipBombs.rb:21:34:21:42 | gzip_path | gzipBombs.rb:25:30:25:38 | gzip_path | provenance | |
| gzipBombs.rb:25:25:25:39 | call to open | gzipBombs.rb:25:3:25:40 | call to zcat | provenance | |
| gzipBombs.rb:25:30:25:38 | gzip_path | gzipBombs.rb:25:25:25:39 | call to open | provenance | |
| zipBombs.rb:4:3:4:14 | zipfile_path | zipBombs.rb:6:25:6:36 | zipfile_path | provenance | |
| zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:4:18:4:30 | ...[...] | provenance | |
| zipBombs.rb:4:18:4:30 | ...[...] | zipBombs.rb:4:3:4:14 | zipfile_path | provenance | |
| zipBombs.rb:6:25:6:36 | zipfile_path | zipBombs.rb:6:3:11:5 | call to open | provenance | |
| zipBombs.rb:6:25:6:36 | zipfile_path | zipBombs.rb:12:25:12:36 | zipfile_path | provenance | |
| zipBombs.rb:12:25:12:36 | zipfile_path | zipBombs.rb:12:3:14:5 | call to open | provenance | |
| zipBombs.rb:12:25:12:36 | zipfile_path | zipBombs.rb:15:33:15:44 | zipfile_path | provenance | |
| zipBombs.rb:15:33:15:44 | zipfile_path | zipBombs.rb:15:11:15:45 | call to open | provenance | |
| zipBombs.rb:15:33:15:44 | zipfile_path | zipBombs.rb:17:18:17:29 | zipfile_path | provenance | |
| zipBombs.rb:17:18:17:29 | zipfile_path | zipBombs.rb:17:3:17:42 | call to read | provenance | |
| zipBombs.rb:17:18:17:29 | zipfile_path | zipBombs.rb:18:18:18:29 | zipfile_path | provenance | |
| zipBombs.rb:18:18:18:29 | zipfile_path | zipBombs.rb:18:3:18:51 | call to extract | provenance | |
| zipBombs.rb:18:18:18:29 | zipfile_path | zipBombs.rb:20:18:20:29 | zipfile_path | provenance | |
| zipBombs.rb:20:18:20:29 | zipfile_path | zipBombs.rb:28:7:28:33 | call to read | provenance | |
| zipBombs.rb:20:18:20:29 | zipfile_path | zipBombs.rb:32:29:32:40 | zipfile_path | provenance | |
| zipBombs.rb:32:29:32:40 | zipfile_path | zipBombs.rb:34:5:34:17 | call to extract | provenance | |
| zipBombs.rb:32:29:32:40 | zipfile_path | zipBombs.rb:35:5:35:31 | call to read | provenance | |
| zipBombs.rb:32:29:32:40 | zipfile_path | zipBombs.rb:39:18:39:29 | zipfile_path | provenance | |
| zipBombs.rb:39:18:39:29 | zipfile_path | zipBombs.rb:41:7:41:31 | call to read | provenance | |
| zipBombs.rb:39:18:39:29 | zipfile_path | zipBombs.rb:42:7:42:19 | call to extract | provenance | |
| zipBombs.rb:39:18:39:29 | zipfile_path | zipBombs.rb:46:10:46:36 | call to read | provenance | |
| zipBombs.rb:39:18:39:29 | zipfile_path | zipBombs.rb:49:29:49:40 | zipfile_path | provenance | |
| zipBombs.rb:49:29:49:40 | zipfile_path | zipBombs.rb:51:8:51:34 | call to read | provenance | |
| zipBombs.rb:49:29:49:40 | zipfile_path | zipBombs.rb:53:29:53:40 | zipfile_path | provenance | |
| zipBombs.rb:53:29:53:40 | zipfile_path | zipBombs.rb:55:5:55:31 | call to read | provenance | |
nodes
| gzipBombs.rb:4:3:4:11 | gzip_path | semmle.label | gzip_path |
| gzipBombs.rb:4:15:4:20 | call to params | semmle.label | call to params |
| gzipBombs.rb:4:15:4:27 | ...[...] | semmle.label | ...[...] |
| gzipBombs.rb:6:3:6:34 | call to open | semmle.label | call to open |
| gzipBombs.rb:6:25:6:33 | gzip_path | semmle.label | gzip_path |
| gzipBombs.rb:7:3:9:5 | call to open | semmle.label | call to open |
| gzipBombs.rb:7:25:7:33 | gzip_path | semmle.label | gzip_path |
| gzipBombs.rb:10:3:14:5 | call to open | semmle.label | call to open |
| gzipBombs.rb:10:25:10:33 | gzip_path | semmle.label | gzip_path |
| gzipBombs.rb:15:22:15:53 | call to open | semmle.label | call to open |
| gzipBombs.rb:15:44:15:52 | gzip_path | semmle.label | gzip_path |
| gzipBombs.rb:20:3:20:50 | call to new | semmle.label | call to new |
| gzipBombs.rb:20:24:20:49 | call to open | semmle.label | call to open |
| gzipBombs.rb:20:34:20:42 | gzip_path | semmle.label | gzip_path |
| gzipBombs.rb:21:3:21:50 | call to new | semmle.label | call to new |
| gzipBombs.rb:21:24:21:49 | call to open | semmle.label | call to open |
| gzipBombs.rb:21:34:21:42 | gzip_path | semmle.label | gzip_path |
| gzipBombs.rb:25:3:25:40 | call to zcat | semmle.label | call to zcat |
| gzipBombs.rb:25:25:25:39 | call to open | semmle.label | call to open |
| gzipBombs.rb:25:30:25:38 | gzip_path | semmle.label | gzip_path |
| zipBombs.rb:4:3:4:14 | zipfile_path | semmle.label | zipfile_path |
| zipBombs.rb:4:18:4:23 | call to params | semmle.label | call to params |
| zipBombs.rb:4:18:4:30 | ...[...] | semmle.label | ...[...] |
| zipBombs.rb:6:3:11:5 | call to open | semmle.label | call to open |
| zipBombs.rb:6:25:6:36 | zipfile_path | semmle.label | zipfile_path |
| zipBombs.rb:12:3:14:5 | call to open | semmle.label | call to open |
| zipBombs.rb:12:25:12:36 | zipfile_path | semmle.label | zipfile_path |
| zipBombs.rb:15:11:15:45 | call to open | semmle.label | call to open |
| zipBombs.rb:15:33:15:44 | zipfile_path | semmle.label | zipfile_path |
| zipBombs.rb:17:3:17:42 | call to read | semmle.label | call to read |
| zipBombs.rb:17:18:17:29 | zipfile_path | semmle.label | zipfile_path |
| zipBombs.rb:18:3:18:51 | call to extract | semmle.label | call to extract |
| zipBombs.rb:18:18:18:29 | zipfile_path | semmle.label | zipfile_path |
| zipBombs.rb:20:18:20:29 | zipfile_path | semmle.label | zipfile_path |
| zipBombs.rb:28:7:28:33 | call to read | semmle.label | call to read |
| zipBombs.rb:32:29:32:40 | zipfile_path | semmle.label | zipfile_path |
| zipBombs.rb:34:5:34:17 | call to extract | semmle.label | call to extract |
| zipBombs.rb:35:5:35:31 | call to read | semmle.label | call to read |
| zipBombs.rb:39:18:39:29 | zipfile_path | semmle.label | zipfile_path |
| zipBombs.rb:41:7:41:31 | call to read | semmle.label | call to read |
| zipBombs.rb:42:7:42:19 | call to extract | semmle.label | call to extract |
| zipBombs.rb:46:10:46:36 | call to read | semmle.label | call to read |
| zipBombs.rb:49:29:49:40 | zipfile_path | semmle.label | zipfile_path |
| zipBombs.rb:51:8:51:34 | call to read | semmle.label | call to read |
| zipBombs.rb:53:29:53:40 | zipfile_path | semmle.label | zipfile_path |
| zipBombs.rb:55:5:55:31 | call to read | semmle.label | call to read |
subpaths
#select
| gzipBombs.rb:6:3:6:34 | call to open | gzipBombs.rb:4:15:4:20 | call to params | gzipBombs.rb:6:3:6:34 | call to open | This file Decompression depends on a $@. | gzipBombs.rb:4:15:4:20 | call to params | potentially untrusted source |
| gzipBombs.rb:7:3:9:5 | call to open | gzipBombs.rb:4:15:4:20 | call to params | gzipBombs.rb:7:3:9:5 | call to open | This file Decompression depends on a $@. | gzipBombs.rb:4:15:4:20 | call to params | potentially untrusted source |
| gzipBombs.rb:10:3:14:5 | call to open | gzipBombs.rb:4:15:4:20 | call to params | gzipBombs.rb:10:3:14:5 | call to open | This file Decompression depends on a $@. | gzipBombs.rb:4:15:4:20 | call to params | potentially untrusted source |
| gzipBombs.rb:15:22:15:53 | call to open | gzipBombs.rb:4:15:4:20 | call to params | gzipBombs.rb:15:22:15:53 | call to open | This file Decompression depends on a $@. | gzipBombs.rb:4:15:4:20 | call to params | potentially untrusted source |
| gzipBombs.rb:20:3:20:50 | call to new | gzipBombs.rb:4:15:4:20 | call to params | gzipBombs.rb:20:3:20:50 | call to new | This file Decompression depends on a $@. | gzipBombs.rb:4:15:4:20 | call to params | potentially untrusted source |
| gzipBombs.rb:21:3:21:50 | call to new | gzipBombs.rb:4:15:4:20 | call to params | gzipBombs.rb:21:3:21:50 | call to new | This file Decompression depends on a $@. | gzipBombs.rb:4:15:4:20 | call to params | potentially untrusted source |
| gzipBombs.rb:25:3:25:40 | call to zcat | gzipBombs.rb:4:15:4:20 | call to params | gzipBombs.rb:25:3:25:40 | call to zcat | This file Decompression depends on a $@. | gzipBombs.rb:4:15:4:20 | call to params | potentially untrusted source |
| zipBombs.rb:6:3:11:5 | call to open | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:6:3:11:5 | call to open | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |
| zipBombs.rb:12:3:14:5 | call to open | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:12:3:14:5 | call to open | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |
| zipBombs.rb:15:11:15:45 | call to open | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:15:11:15:45 | call to open | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |
| zipBombs.rb:17:3:17:42 | call to read | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:17:3:17:42 | call to read | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |
| zipBombs.rb:18:3:18:51 | call to extract | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:18:3:18:51 | call to extract | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |
| zipBombs.rb:28:7:28:33 | call to read | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:28:7:28:33 | call to read | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |
| zipBombs.rb:34:5:34:17 | call to extract | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:34:5:34:17 | call to extract | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |
| zipBombs.rb:35:5:35:31 | call to read | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:35:5:35:31 | call to read | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |
| zipBombs.rb:41:7:41:31 | call to read | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:41:7:41:31 | call to read | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |
| zipBombs.rb:42:7:42:19 | call to extract | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:42:7:42:19 | call to extract | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |
| zipBombs.rb:46:10:46:36 | call to read | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:46:10:46:36 | call to read | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |
| zipBombs.rb:51:8:51:34 | call to read | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:51:8:51:34 | call to read | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |
| zipBombs.rb:55:5:55:31 | call to read | zipBombs.rb:4:18:4:23 | call to params | zipBombs.rb:55:5:55:31 | call to read | This file Decompression depends on a $@. | zipBombs.rb:4:18:4:23 | call to params | potentially untrusted source |

View File

@@ -0,0 +1 @@
experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql

View File

@@ -0,0 +1,27 @@
require 'zlib'
class TestController < ActionController::Base
gzip_path = params[:path]
Zlib::GzipReader.open(gzip_path).read
Zlib::GzipReader.open(gzip_path) do |uncompressedfile|
puts uncompressedfile.read
end
Zlib::GzipReader.open(gzip_path) do |uncompressedfile|
uncompressedfile.each do |entry|
puts entry
end
end
uncompressedfile = Zlib::GzipReader.open(gzip_path)
uncompressedfile.each do |entry|
puts entry
end
Zlib::GzipReader.new(File.open(gzip_path, 'rb')).read
Zlib::GzipReader.new(File.open(gzip_path, 'rb')).each do |entry|
puts entry
end
Zlib::GzipReader.zcat(open(gzip_path))
end

View File

@@ -0,0 +1,57 @@
require 'zip'
class TestController < ActionController::Base
zipfile_path = params[:path]
Zip::InputStream.open(zipfile_path) do |input|
while (entry = input.get_next_entry)
puts :file_name, entry.name
input
end
end
Zip::InputStream.open(zipfile_path) do |input|
input.read
end
input = Zip::InputStream.open(zipfile_path)
Zip::File.open(zipfile_path).read "10GB"
Zip::File.open(zipfile_path).extract "10GB", "./"
Zip::File.open(zipfile_path) do |zip_file|
# Handle entries one by one
zip_file.each do |entry|
puts "Extracting #{entry.name}"
raise 'File too large when extracted' if entry.size > MAX_SIZE
# Extract to file or directory based on name in the archive
entry.extract
# Read into memory
entry.get_input_stream.read
end
end
zip_file = Zip::File.open(zipfile_path)
zip_file.each do |entry|
entry.extract
entry.get_input_stream.read
end
# Find specific entry
Zip::File.open(zipfile_path) do |zip_file|
zip_file.glob('*.xml').each do |entry|
zip_file.read(entry.name)
entry.extract
end
entry = zip_file.glob('*.csv').first
raise 'File too large when extracted' if entry.size > MAX_SIZE
puts entry.get_input_stream.read
end
zip_file = Zip::File.open(zipfile_path)
entry = zip_file.glob('*.csv')
puts entry.get_input_stream.read
zip_file = Zip::File.open(zipfile_path)
zip_file.glob('*') do |entry|
entry.get_input_stream.read
end
end