Skip to content

Commit 042133a

Browse files
committed
add queries for more popular libs
1 parent f715a34 commit 042133a

11 files changed

Lines changed: 593 additions & 18 deletions

cpp/ql/src/experimental/Security/CWE/CWE-409-DecompressionBomb/DecompressionBomb.qhelp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
<overview>
66
<p>Extracting Compressed files with any compression algorithm like gzip can cause to denial of service attacks.</p>
77
<p>Attackers can compress a huge file which created by repeated similiar byte and convert it to a small compressed file.</p>
8-
98
</overview>
109
<recommendation>
1110

@@ -25,8 +24,13 @@ An Unsafe Approach can be this example which we don't check for uncompressed siz
2524
<sample src="example_bad.cpp" />
2625

2726
</example>
27+
2828
<references>
2929

30+
<li>
31+
<a href="https://zlib.net/manual.html">Zlib Documentation</a>
32+
</li>
33+
3034
<li>
3135
<a href="https://www.bamsoftware.com/hacks/zipbomb/">A great research to gain more impact by this kind of attacks</a>
3236
</li>
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* @name User-controlled file decompression
3+
* @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @security-severity 7.8
7+
* @precision high
8+
* @id cpp/user-controlled-file-decompression-brotli
9+
* @tags security
10+
* experimental
11+
* external/cwe/cwe-409
12+
*/
13+
14+
// https://github.com/google/brotli
15+
import cpp
16+
import semmle.code.cpp.ir.dataflow.TaintTracking
17+
import semmle.code.cpp.security.FlowSources
18+
import semmle.code.cpp.commons.File
19+
20+
/**
21+
* A Pointer Variable is used in Flow source
22+
*/
23+
private class PointerVar extends VariableAccess {
24+
PointerVar() { this.getType() instanceof PointerType }
25+
}
26+
27+
/**
28+
* A Pointer Variable is used in Flow source
29+
*/
30+
private class Uint8Var extends VariableAccess {
31+
Uint8Var() { this.getType() instanceof UInt8_t }
32+
}
33+
34+
/**
35+
* A ZSTD_inBuffer Variable is used in Flow source
36+
*/
37+
private class ZSTDinBufferVar extends VariableAccess {
38+
ZSTDinBufferVar() { this.getType().hasName("ZSTD_inBuffer") }
39+
}
40+
41+
/**
42+
* The `ZSTD_decompress_usingDDict` function is used in Flow sink
43+
* Ref: https://www.brotli.org/decode.html#af68
44+
*/
45+
private class BrotliDecoderDecompressFunction extends Function {
46+
BrotliDecoderDecompressFunction() { this.hasGlobalName(["BrotliDecoderDecompress"]) }
47+
}
48+
49+
/**
50+
* The `BrotliDecoderDecompressStream` function is used in Flow sink
51+
* Ref: https://www.brotli.org/decode.html#a234
52+
*/
53+
private class BrotliDecoderDecompressStreamFunction extends Function {
54+
BrotliDecoderDecompressStreamFunction() { this.hasGlobalName(["BrotliDecoderDecompressStream"]) }
55+
}
56+
57+
module BrotliTaintConfig implements DataFlow::StateConfigSig {
58+
class FlowState = DataFlow::FlowState;
59+
60+
predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
61+
exists(FunctionCall fc | fc.getTarget() instanceof AllocationFunction |
62+
fc = source.asExpr() and
63+
state = ""
64+
)
65+
or
66+
exists(FunctionCall fc | fopenCall(fc) |
67+
fc = source.asExpr() and
68+
state = ""
69+
)
70+
or
71+
source.asExpr() instanceof PointerVar and
72+
state = ""
73+
or
74+
source.asExpr() instanceof Uint8Var and
75+
state = ""
76+
}
77+
78+
predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
79+
exists(FunctionCall fc | fc.getTarget() instanceof BrotliDecoderDecompressStreamFunction |
80+
fc.getArgument(2) = sink.asExpr() and
81+
state = ""
82+
)
83+
or
84+
exists(FunctionCall fc | fc.getTarget() instanceof BrotliDecoderDecompressFunction |
85+
fc.getArgument(1) = sink.asExpr() and
86+
state = ""
87+
)
88+
}
89+
90+
predicate isAdditionalFlowStep(
91+
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
92+
DataFlow::FlowState state2
93+
) {
94+
none()
95+
}
96+
97+
predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { none() }
98+
}
99+
100+
module BrotliTaint = TaintTracking::GlobalWithState<BrotliTaintConfig>;
101+
102+
import BrotliTaint::PathGraph
103+
104+
from BrotliTaint::PathNode source, BrotliTaint::PathNode sink
105+
where BrotliTaint::flowPath(source, sink)
106+
select sink.getNode(), source, sink, "This Decompression depends on a $@.", source.getNode(),
107+
"potentially untrusted source"
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/**
2+
* @name User-controlled file decompression
3+
* @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @security-severity 7.8
7+
* @precision high
8+
* @id cpp/user-controlled-file-decompression-bzip2
9+
* experimental
10+
* external/cwe/cwe-409
11+
*/
12+
13+
import cpp
14+
import semmle.code.cpp.ir.dataflow.TaintTracking
15+
import semmle.code.cpp.security.FlowSources
16+
import semmle.code.cpp.commons.File
17+
18+
/**
19+
* A `bz_stream` Variable as a Flow source
20+
*/
21+
private class BzStreamVar extends VariableAccess {
22+
BzStreamVar() { this.getType().hasName("bz_stream") }
23+
}
24+
25+
/**
26+
* A `BZFILE` Variable as a Flow source
27+
*/
28+
private class BZFILEVar extends VariableAccess {
29+
BZFILEVar() { this.getType().hasName("BZFILE") }
30+
}
31+
32+
/**
33+
* The `BZ2_bzopen`,`BZ2_bzdopen` functions as a Flow source
34+
*/
35+
private class BZ2BzopenFunction extends Function {
36+
BZ2BzopenFunction() { this.hasGlobalName(["BZ2_bzopen", "BZ2_bzdopen"]) }
37+
}
38+
39+
/**
40+
* The `BZ2_bzDecompress` function as a Flow source
41+
*/
42+
private class BZ2BzDecompressFunction extends Function {
43+
BZ2BzDecompressFunction() { this.hasGlobalName(["BZ2_bzDecompress"]) }
44+
}
45+
46+
/**
47+
* The `BZ2_bzReadOpen` function
48+
*/
49+
private class BZ2BzReadOpenFunction extends Function {
50+
BZ2BzReadOpenFunction() { this.hasGlobalName(["BZ2_bzReadOpen"]) }
51+
}
52+
53+
/**
54+
* The `BZ2_bzRead` function is used in Flow sink
55+
*/
56+
private class BZ2BzReadFunction extends Function {
57+
BZ2BzReadFunction() { this.hasGlobalName("BZ2_bzRead") }
58+
}
59+
60+
/**
61+
* The `BZ2_bzRead` function is used in Flow sink
62+
*/
63+
private class BZ2BzBuffToBuffDecompressFunction extends Function {
64+
BZ2BzBuffToBuffDecompressFunction() { this.hasGlobalName("BZ2_bzBuffToBuffDecompress") }
65+
}
66+
67+
/**
68+
* https://www.sourceware.org/bzip2/manual/manual.html
69+
*/
70+
module Bzip2TaintConfig implements DataFlow::StateConfigSig {
71+
class FlowState = DataFlow::FlowState;
72+
73+
predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
74+
source.asExpr() instanceof BzStreamVar and
75+
state = ""
76+
or
77+
source.asExpr() instanceof BZFILEVar and
78+
state = ""
79+
or
80+
// will flow into BZ2BzReadOpenFunction
81+
exists(FunctionCall fc | fopenCall(fc) |
82+
fc = source.asExpr() and
83+
state = ""
84+
)
85+
}
86+
87+
predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
88+
exists(FunctionCall fc | fc.getTarget() instanceof BZ2BzDecompressFunction |
89+
fc.getArgument(0) = sink.asExpr() and
90+
state = ""
91+
)
92+
or
93+
exists(FunctionCall fc | fc.getTarget() instanceof BZ2BzReadFunction |
94+
fc.getArgument(1) = sink.asExpr() and
95+
state = ""
96+
)
97+
or
98+
exists(FunctionCall fc | fc.getTarget() instanceof BZ2BzBuffToBuffDecompressFunction |
99+
fc.getArgument(2) = sink.asExpr() and
100+
state = ""
101+
)
102+
}
103+
104+
predicate isAdditionalFlowStep(
105+
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
106+
DataFlow::FlowState state2
107+
) {
108+
exists(FunctionCall fc | fc.getTarget() instanceof BZ2BzReadOpenFunction |
109+
node1.asExpr() = fc.getArgument(1) and
110+
node2.asExpr() = fc and
111+
state1 = "" and
112+
state2 = ""
113+
)
114+
}
115+
116+
predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { none() }
117+
}
118+
119+
module Bzip2Taint = TaintTracking::GlobalWithState<Bzip2TaintConfig>;
120+
121+
import Bzip2Taint::PathGraph
122+
123+
from Bzip2Taint::PathNode source, Bzip2Taint::PathNode sink
124+
where Bzip2Taint::flowPath(source, sink)
125+
select sink.getNode(), source, sink, "This Decompressiondepends on a $@.", source.getNode(),
126+
"potentially untrusted source"
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/**
2+
* @name User-controlled file decompression
3+
* @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @security-severity 7.8
7+
* @precision high
8+
* @id cpp/user-controlled-file-decompression-minizip
9+
* @tags security
10+
* experimental
11+
* external/cwe/cwe-409
12+
*/
13+
14+
import cpp
15+
import semmle.code.cpp.ir.dataflow.TaintTracking
16+
import semmle.code.cpp.security.FlowSources
17+
18+
/**
19+
* A `unzFile` Variable as a Flow source
20+
*/
21+
private class UnzFileVar extends VariableAccess {
22+
UnzFileVar() { this.getType().hasName("unzFile") }
23+
}
24+
25+
/**
26+
* The `UnzOpen` function as a Flow source
27+
*/
28+
private class UnzOpenFunction extends Function {
29+
UnzOpenFunction() { this.hasGlobalName(["UnzOpen", "unzOpen64", "unzOpen2", "unzOpen2_64"]) }
30+
}
31+
32+
/**
33+
* The `mz_stream_open` function is used in Flow source
34+
*/
35+
private class MzStreamOpenFunction extends Function {
36+
MzStreamOpenFunction() { this.hasGlobalName("mz_stream_open") }
37+
}
38+
39+
/**
40+
* The `unzReadCurrentFile` function is used in Flow sink
41+
*/
42+
private class UnzReadCurrentFileFunction extends Function {
43+
UnzReadCurrentFileFunction() { this.hasGlobalName(["unzReadCurrentFile"]) }
44+
}
45+
46+
module MiniZipTaintConfig implements DataFlow::StateConfigSig {
47+
class FlowState = DataFlow::FlowState;
48+
49+
predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
50+
exists(FunctionCall fc | fc.getTarget() instanceof UnzOpenFunction |
51+
fc.getArgument(0) = source.asExpr() and
52+
state = "unzFile"
53+
)
54+
or
55+
source.asExpr() instanceof UnzFileVar and
56+
state = "unzFile"
57+
or
58+
// TO Check
59+
exists(FunctionCall fc | fc.getTarget() instanceof MzStreamOpenFunction |
60+
fc.getArgument(0).getEnclosingVariable() = source.asVariable() and
61+
state = "MzStream"
62+
)
63+
or
64+
// TO Check
65+
exists(FunctionCall fc | fc.getTarget() instanceof MzStreamOpenFunction |
66+
fc.getArgument(0).getEnclosingVariable() = source.asVariable() and
67+
state = "MzStream"
68+
)
69+
}
70+
71+
predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
72+
exists(FunctionCall fc | fc.getTarget() instanceof UnzReadCurrentFileFunction |
73+
fc.getArgument(0) = sink.asExpr() and
74+
state = "unzFile"
75+
// and not sanitizer(fc)
76+
)
77+
}
78+
79+
predicate isAdditionalFlowStep(
80+
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
81+
DataFlow::FlowState state2
82+
) {
83+
exists(FunctionCall fc | fc.getTarget() instanceof UnzOpenFunction |
84+
node1.asExpr() = fc.getArgument(0) and
85+
node2.asExpr() = fc and
86+
state1 = "" and
87+
state2 = "unzFile"
88+
)
89+
}
90+
91+
predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { none() }
92+
}
93+
94+
95+
module MiniZipTaint = TaintTracking::GlobalWithState<MiniZipTaintConfig>;
96+
97+
import MiniZipTaint::PathGraph
98+
99+
from MiniZipTaint::PathNode source, MiniZipTaint::PathNode sink
100+
where MiniZipTaint::flowPath(source, sink)
101+
select sink.getNode(), source, sink, "This Decompressiondepends on a $@.", source.getNode(),
102+
"potentially untrusted source"

0 commit comments

Comments
 (0)