-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13553 from am0o0/amammad-go-bombs
Go: Decompression Bombs
- Loading branch information
Showing
26 changed files
with
2,508 additions
and
0 deletions.
There are no files selected for viewing
33 changes: 33 additions & 0 deletions
33
go/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.qhelp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<!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. Also you can limit the size of reader buffer.</p> | ||
|
||
</recommendation> | ||
<example> | ||
<p> | ||
Using "io.LimitReader" and "io.CopyN" are the best option to prevent decompression bomb attacks. | ||
</p> | ||
<sample src="example_good.go"/> | ||
|
||
<sample src="example_good_2.go" /> | ||
</example> | ||
<references> | ||
|
||
<li> | ||
<a href="https://github.com/russellhaering/gosaml2/security/advisories/GHSA-6gc3-crp7-25w5">CVE-2023-26483 </a> | ||
</li> | ||
<li> | ||
<a href="https://www.bamsoftware.com/hacks/zipbomb/">A great research to gain more impact by this kind of attacks</a> | ||
</li> | ||
|
||
</references> | ||
</qhelp> |
21 changes: 21 additions & 0 deletions
21
go/ql/src/experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/** | ||
* @name Uncontrolled file decompression | ||
* @description Uncontrolled 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 go/uncontrolled-file-decompression | ||
* @tags security | ||
* experimental | ||
* external/cwe/cwe-409 | ||
*/ | ||
|
||
import go | ||
import experimental.frameworks.DecompressionBombs | ||
import DecompressionBomb::Flow::PathGraph | ||
|
||
from DecompressionBomb::Flow::PathNode source, DecompressionBomb::Flow::PathNode sink | ||
where DecompressionBomb::Flow::flowPath(source, sink) | ||
select sink.getNode(), source, sink, "This decompression is $@.", source.getNode(), | ||
"decompressing compressed data without managing output size" |
30 changes: 30 additions & 0 deletions
30
go/ql/src/experimental/CWE-522-DecompressionBombs/example_good.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package main | ||
|
||
import ( | ||
"archive/zip" | ||
"fmt" | ||
"io" | ||
"os" | ||
) | ||
|
||
func ZipOpenReader(filename string) { | ||
// Open the zip file | ||
r, _ := zip.OpenReader(filename) | ||
var totalBytes int64 | ||
for _, f := range r.File { | ||
rc, _ := f.Open() | ||
totalBytes = 0 | ||
for { | ||
result, _ := io.CopyN(os.Stdout, rc, 68) | ||
if result == 0 { | ||
break | ||
} | ||
totalBytes = totalBytes + result | ||
if totalBytes > 1024*1024 { | ||
fmt.Print(totalBytes) | ||
_ = rc.Close() | ||
break | ||
} | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
go/ql/src/experimental/CWE-522-DecompressionBombs/example_good_2.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package main | ||
|
||
import ( | ||
"compress/gzip" | ||
"io" | ||
"os" | ||
) | ||
|
||
func safeReader() { | ||
var src io.Reader | ||
src, _ = os.Open("filename") | ||
gzipR, _ := gzip.NewReader(src) | ||
dstF, _ := os.OpenFile("./test", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) | ||
defer dstF.Close() | ||
var newSrc io.Reader | ||
newSrc = io.LimitReader(gzipR, 1024*1024*1024*5) | ||
_, _ = io.Copy(dstF, newSrc) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/** | ||
* Provides a taint tracking configuration for reasoning about decompression bomb vulnerabilities. | ||
*/ | ||
|
||
import go | ||
|
||
class MimeMultipartFileHeader extends UntrustedFlowSource::Range { | ||
MimeMultipartFileHeader() { | ||
exists(DataFlow::FieldReadNode frn | this = frn | | ||
frn.getField().hasQualifiedName("mime/multipart", "FileHeader", ["Filename", "Header"]) | ||
) | ||
or | ||
exists(DataFlow::Method m | | ||
m.hasQualifiedName("mime/multipart", "FileHeader", "Open") and | ||
this = m.getACall().getResult(0) | ||
) | ||
or | ||
exists(DataFlow::FieldReadNode frn | | ||
frn.getField().hasQualifiedName("mime/multipart", "Form", "Value") | ||
) | ||
} | ||
} | ||
|
||
/** Provides a taint tracking configuration for reasoning about decompression bomb vulnerabilities. */ | ||
module DecompressionBomb { | ||
import experimental.frameworks.DecompressionBombsCustomizations | ||
|
||
module Config implements DataFlow::StateConfigSig { | ||
class FlowState = DecompressionBombs::FlowState; | ||
|
||
predicate isSource(DataFlow::Node source, FlowState state) { | ||
source instanceof UntrustedFlowSource and | ||
state = "" | ||
} | ||
|
||
predicate isSink(DataFlow::Node sink, FlowState state) { | ||
sink instanceof DecompressionBombs::Sink and | ||
state = | ||
[ | ||
"ZstdNewReader", "XzNewReader", "GzipNewReader", "PgzipNewReader", "S2NewReader", | ||
"SnappyNewReader", "ZlibNewReader", "FlateNewReader", "Bzip2NewReader", "ZipOpenReader", | ||
"ZipKlauspost" | ||
] | ||
} | ||
|
||
predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) { | ||
exists(DecompressionBombs::AdditionalTaintStep addStep | | ||
addStep.isAdditionalFlowStep(fromNode, toNode) | ||
) | ||
} | ||
|
||
predicate isAdditionalFlowStep( | ||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState | ||
) { | ||
exists(DecompressionBombs::AdditionalTaintStep addStep | | ||
addStep.isAdditionalFlowStep(fromNode, fromState, toNode, toState) | ||
) | ||
} | ||
} | ||
|
||
/** Tracks taint flow for reasoning about decompression bomb vulnerabilities. */ | ||
module Flow = TaintTracking::GlobalWithState<Config>; | ||
} |
Oops, something went wrong.