mirror of
https://github.com/github/codeql.git
synced 2026-02-20 08:53:49 +01:00
Merge pull request #13556 from am0o0/amammad-ruby-bombs
Ruby: Decompression Bombs
This commit is contained in:
@@ -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>
|
||||
@@ -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"
|
||||
@@ -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()
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user