add queries for more popular libs

This commit is contained in:
amammad
2023-07-03 09:12:37 +10:00
parent f715a3437b
commit 042133a991
11 changed files with 593 additions and 18 deletions

View File

@@ -5,7 +5,6 @@
<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>
@@ -25,8 +24,13 @@ An Unsafe Approach can be this example which we don't check for uncompressed siz
<sample src="example_bad.cpp" />
</example>
<references>
<li>
<a href="https://zlib.net/manual.html">Zlib Documentation</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>

View File

@@ -0,0 +1,107 @@
/**
* @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 cpp/user-controlled-file-decompression-brotli
* @tags security
* experimental
* external/cwe/cwe-409
*/
// https://github.com/google/brotli
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.commons.File
/**
* A Pointer Variable is used in Flow source
*/
private class PointerVar extends VariableAccess {
PointerVar() { this.getType() instanceof PointerType }
}
/**
* A Pointer Variable is used in Flow source
*/
private class Uint8Var extends VariableAccess {
Uint8Var() { this.getType() instanceof UInt8_t }
}
/**
* A ZSTD_inBuffer Variable is used in Flow source
*/
private class ZSTDinBufferVar extends VariableAccess {
ZSTDinBufferVar() { this.getType().hasName("ZSTD_inBuffer") }
}
/**
* The `ZSTD_decompress_usingDDict` function is used in Flow sink
* Ref: https://www.brotli.org/decode.html#af68
*/
private class BrotliDecoderDecompressFunction extends Function {
BrotliDecoderDecompressFunction() { this.hasGlobalName(["BrotliDecoderDecompress"]) }
}
/**
* The `BrotliDecoderDecompressStream` function is used in Flow sink
* Ref: https://www.brotli.org/decode.html#a234
*/
private class BrotliDecoderDecompressStreamFunction extends Function {
BrotliDecoderDecompressStreamFunction() { this.hasGlobalName(["BrotliDecoderDecompressStream"]) }
}
module BrotliTaintConfig implements DataFlow::StateConfigSig {
class FlowState = DataFlow::FlowState;
predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
exists(FunctionCall fc | fc.getTarget() instanceof AllocationFunction |
fc = source.asExpr() and
state = ""
)
or
exists(FunctionCall fc | fopenCall(fc) |
fc = source.asExpr() and
state = ""
)
or
source.asExpr() instanceof PointerVar and
state = ""
or
source.asExpr() instanceof Uint8Var and
state = ""
}
predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
exists(FunctionCall fc | fc.getTarget() instanceof BrotliDecoderDecompressStreamFunction |
fc.getArgument(2) = sink.asExpr() and
state = ""
)
or
exists(FunctionCall fc | fc.getTarget() instanceof BrotliDecoderDecompressFunction |
fc.getArgument(1) = sink.asExpr() and
state = ""
)
}
predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
none()
}
predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { none() }
}
module BrotliTaint = TaintTracking::GlobalWithState<BrotliTaintConfig>;
import BrotliTaint::PathGraph
from BrotliTaint::PathNode source, BrotliTaint::PathNode sink
where BrotliTaint::flowPath(source, sink)
select sink.getNode(), source, sink, "This Decompression depends on a $@.", source.getNode(),
"potentially untrusted source"

View File

@@ -0,0 +1,126 @@
/**
* @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 cpp/user-controlled-file-decompression-bzip2
* experimental
* external/cwe/cwe-409
*/
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.commons.File
/**
* A `bz_stream` Variable as a Flow source
*/
private class BzStreamVar extends VariableAccess {
BzStreamVar() { this.getType().hasName("bz_stream") }
}
/**
* A `BZFILE` Variable as a Flow source
*/
private class BZFILEVar extends VariableAccess {
BZFILEVar() { this.getType().hasName("BZFILE") }
}
/**
* The `BZ2_bzopen`,`BZ2_bzdopen` functions as a Flow source
*/
private class BZ2BzopenFunction extends Function {
BZ2BzopenFunction() { this.hasGlobalName(["BZ2_bzopen", "BZ2_bzdopen"]) }
}
/**
* The `BZ2_bzDecompress` function as a Flow source
*/
private class BZ2BzDecompressFunction extends Function {
BZ2BzDecompressFunction() { this.hasGlobalName(["BZ2_bzDecompress"]) }
}
/**
* The `BZ2_bzReadOpen` function
*/
private class BZ2BzReadOpenFunction extends Function {
BZ2BzReadOpenFunction() { this.hasGlobalName(["BZ2_bzReadOpen"]) }
}
/**
* The `BZ2_bzRead` function is used in Flow sink
*/
private class BZ2BzReadFunction extends Function {
BZ2BzReadFunction() { this.hasGlobalName("BZ2_bzRead") }
}
/**
* The `BZ2_bzRead` function is used in Flow sink
*/
private class BZ2BzBuffToBuffDecompressFunction extends Function {
BZ2BzBuffToBuffDecompressFunction() { this.hasGlobalName("BZ2_bzBuffToBuffDecompress") }
}
/**
* https://www.sourceware.org/bzip2/manual/manual.html
*/
module Bzip2TaintConfig implements DataFlow::StateConfigSig {
class FlowState = DataFlow::FlowState;
predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
source.asExpr() instanceof BzStreamVar and
state = ""
or
source.asExpr() instanceof BZFILEVar and
state = ""
or
// will flow into BZ2BzReadOpenFunction
exists(FunctionCall fc | fopenCall(fc) |
fc = source.asExpr() and
state = ""
)
}
predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
exists(FunctionCall fc | fc.getTarget() instanceof BZ2BzDecompressFunction |
fc.getArgument(0) = sink.asExpr() and
state = ""
)
or
exists(FunctionCall fc | fc.getTarget() instanceof BZ2BzReadFunction |
fc.getArgument(1) = sink.asExpr() and
state = ""
)
or
exists(FunctionCall fc | fc.getTarget() instanceof BZ2BzBuffToBuffDecompressFunction |
fc.getArgument(2) = sink.asExpr() and
state = ""
)
}
predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
exists(FunctionCall fc | fc.getTarget() instanceof BZ2BzReadOpenFunction |
node1.asExpr() = fc.getArgument(1) and
node2.asExpr() = fc and
state1 = "" and
state2 = ""
)
}
predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { none() }
}
module Bzip2Taint = TaintTracking::GlobalWithState<Bzip2TaintConfig>;
import Bzip2Taint::PathGraph
from Bzip2Taint::PathNode source, Bzip2Taint::PathNode sink
where Bzip2Taint::flowPath(source, sink)
select sink.getNode(), source, sink, "This Decompressiondepends on a $@.", source.getNode(),
"potentially untrusted source"

View File

@@ -0,0 +1,102 @@
/**
* @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 cpp/user-controlled-file-decompression-minizip
* @tags security
* experimental
* external/cwe/cwe-409
*/
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.security.FlowSources
/**
* A `unzFile` Variable as a Flow source
*/
private class UnzFileVar extends VariableAccess {
UnzFileVar() { this.getType().hasName("unzFile") }
}
/**
* The `UnzOpen` function as a Flow source
*/
private class UnzOpenFunction extends Function {
UnzOpenFunction() { this.hasGlobalName(["UnzOpen", "unzOpen64", "unzOpen2", "unzOpen2_64"]) }
}
/**
* The `mz_stream_open` function is used in Flow source
*/
private class MzStreamOpenFunction extends Function {
MzStreamOpenFunction() { this.hasGlobalName("mz_stream_open") }
}
/**
* The `unzReadCurrentFile` function is used in Flow sink
*/
private class UnzReadCurrentFileFunction extends Function {
UnzReadCurrentFileFunction() { this.hasGlobalName(["unzReadCurrentFile"]) }
}
module MiniZipTaintConfig implements DataFlow::StateConfigSig {
class FlowState = DataFlow::FlowState;
predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
exists(FunctionCall fc | fc.getTarget() instanceof UnzOpenFunction |
fc.getArgument(0) = source.asExpr() and
state = "unzFile"
)
or
source.asExpr() instanceof UnzFileVar and
state = "unzFile"
or
// TO Check
exists(FunctionCall fc | fc.getTarget() instanceof MzStreamOpenFunction |
fc.getArgument(0).getEnclosingVariable() = source.asVariable() and
state = "MzStream"
)
or
// TO Check
exists(FunctionCall fc | fc.getTarget() instanceof MzStreamOpenFunction |
fc.getArgument(0).getEnclosingVariable() = source.asVariable() and
state = "MzStream"
)
}
predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
exists(FunctionCall fc | fc.getTarget() instanceof UnzReadCurrentFileFunction |
fc.getArgument(0) = sink.asExpr() and
state = "unzFile"
// and not sanitizer(fc)
)
}
predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
exists(FunctionCall fc | fc.getTarget() instanceof UnzOpenFunction |
node1.asExpr() = fc.getArgument(0) and
node2.asExpr() = fc and
state1 = "" and
state2 = "unzFile"
)
}
predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { none() }
}
module MiniZipTaint = TaintTracking::GlobalWithState<MiniZipTaintConfig>;
import MiniZipTaint::PathGraph
from MiniZipTaint::PathNode source, MiniZipTaint::PathNode sink
where MiniZipTaint::flowPath(source, sink)
select sink.getNode(), source, sink, "This Decompressiondepends on a $@.", source.getNode(),
"potentially untrusted source"

View File

@@ -0,0 +1,100 @@
/**
* @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 cpp/user-controlled-file-decompression-xz
* @tags security
* experimental
* external/cwe/cwe-409
*/
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.security.FlowSources
/**
* A Pointer Variable as a Flow source
*/
private class Uint8Var extends VariableAccess {
Uint8Var() { this.getType() instanceof UInt8_t }
}
/**
* A `lzma_stream` Variable as a Flow source
*/
private class LzmaStreamVar extends VariableAccess {
LzmaStreamVar() { this.getType().hasName("lzma_stream") }
}
/**
* The `lzma_*_decoder` function is used as a required condition for decompression
*/
private class LzmaDecoderFunction extends Function {
LzmaDecoderFunction() {
this.hasGlobalName(["lzma_stream_decoder", "lzma_auto_decoder", "lzma_alone_decoder"])
}
}
/**
* The `lzma_code` function is used in Flow sink
*/
private class LzmaCodeFunction extends Function {
LzmaCodeFunction() { this.hasGlobalName(["lzma_code"]) }
}
/**
* The `lzma_stream_buffer_decode` function is used in Flow sink
*/
private class LzmaStreamBufferDecodeFunction extends Function {
LzmaStreamBufferDecodeFunction() { this.hasGlobalName(["lzma_stream_buffer_decode"]) }
}
/**
* https://github.com/tukaani-project/xz
*/
module XzTaintConfig implements DataFlow::StateConfigSig {
class FlowState = DataFlow::FlowState;
predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
source.asExpr() instanceof LzmaStreamVar and
state = ""
or
source.asExpr() instanceof Uint8Var and
state = ""
// and not exists(FunctionCall fc | fc.getTarget() instanceof LzmaStreamDecoderFunction)
}
predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
exists(FunctionCall fc | fc.getTarget() instanceof LzmaStreamBufferDecodeFunction |
fc.getArgument(1) = sink.asExpr() and
state = ""
)
or
exists(FunctionCall fc | fc.getTarget() instanceof LzmaCodeFunction |
fc.getArgument(0) = sink.asExpr() and
state = ""
) and
exists(FunctionCall fc2 | fc2.getTarget() instanceof LzmaDecoderFunction)
}
predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
none()
}
predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { none() }
}
module XzTaint = TaintTracking::GlobalWithState<XzTaintConfig>;
import XzTaint::PathGraph
from XzTaint::PathNode source, XzTaint::PathNode sink
where XzTaint::flowPath(source, sink)
select sink.getNode(), source, sink, "This Decompressiondepends on a $@.", source.getNode(),
"potentially untrusted source"

View File

@@ -0,0 +1,140 @@
/**
* @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 cpp/user-controlled-file-decompression-zstd
* @tags security
* experimental
* external/cwe/cwe-409
*/
// https://github.com/facebook/zstd/blob/dev/examples/streaming_decompression.c
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.commons.File
// /**
// * A Pointer Variable as a Flow source
// */
// private class PointerVar extends VariableAccess {
// PointerVar() { this.getType() instanceof PointerType }
// }
/**
* A ZSTD_inBuffer Variable as a Flow source
*/
private class ZSTDinBufferVar extends VariableAccess {
ZSTDinBufferVar() { this.getType().hasName("ZSTD_inBuffer") }
}
/**
* A ZSTD_inBuffer_s Variable as a Flow source
*/
private class ZSTDinBufferSVar extends VariableAccess {
ZSTDinBufferSVar() { this.getType().hasName("ZSTD_inBuffer_s") }
}
/**
* The `ZSTD_decompress` function is used in Flow sink
*/
private class ZSTDDecompressFunction extends Function {
ZSTDDecompressFunction() { this.hasGlobalName(["ZSTD_decompress"]) }
}
/**
* The `ZSTD_decompressDCtx` function is used in Flow sink
*/
private class ZSTDDecompressDCtxFunction extends Function {
ZSTDDecompressDCtxFunction() { this.hasGlobalName(["ZSTD_decompressDCtx"]) }
}
/**
* The `ZSTD_decompressStream` function is used in Flow sink
*/
private class ZSTDDecompressStreamFunction extends Function {
ZSTDDecompressStreamFunction() { this.hasGlobalName(["ZSTD_decompressStream"]) }
}
/**
* The `ZSTD_decompress_usingDDict` function is used in Flow sink
*/
private class ZSTDDecompressUsingDictFunction extends Function {
ZSTDDecompressUsingDictFunction() { this.hasGlobalName(["ZSTD_decompress_usingDDict"]) }
}
/**
* The `ZSTD_decompress_usingDDict` function is used in Flow sink
*/
private class ZSTDDecompressUsingDDictFunction extends Function {
ZSTDDecompressUsingDDictFunction() { this.hasGlobalName(["ZSTD_decompress_usingDDict"]) }
}
module ZstdTaintConfig implements DataFlow::StateConfigSig {
class FlowState = DataFlow::FlowState;
predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
exists(FunctionCall fc | fc.getTarget() instanceof AllocationFunction |
fc = source.asExpr() and
state = ""
)
or
exists(FunctionCall fc | fopenCall(fc) |
fc = source.asExpr() and
state = ""
)
or
source.asExpr() instanceof ZSTDinBufferSVar and
state = ""
or
source.asExpr() instanceof ZSTDinBufferVar and
state = ""
}
predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
exists(FunctionCall fc | fc.getTarget() instanceof ZSTDDecompressFunction |
fc.getArgument(2) = sink.asExpr() and
state = ""
)
or
exists(FunctionCall fc | fc.getTarget() instanceof ZSTDDecompressDCtxFunction |
fc.getArgument(3) = sink.asExpr() and
state = ""
)
or
exists(FunctionCall fc | fc.getTarget() instanceof ZSTDDecompressStreamFunction |
fc.getArgument(2) = sink.asExpr() and
state = ""
)
or
exists(FunctionCall fc | fc.getTarget() instanceof ZSTDDecompressUsingDictFunction |
fc.getArgument(3) = sink.asExpr() and
state = ""
)
or
exists(FunctionCall fc | fc.getTarget() instanceof ZSTDDecompressUsingDDictFunction |
fc.getArgument(3) = sink.asExpr() and
state = ""
)
}
predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
none()
}
predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) { none() }
}
module ZstdTaint = TaintTracking::GlobalWithState<ZstdTaintConfig>;
import ZstdTaint::PathGraph
from ZstdTaint::PathNode source, ZstdTaint::PathNode sink
where ZstdTaint::flowPath(source, sink)
select sink.getNode(), source, sink, "This Decompression depends on a $@.", source.getNode(),
"potentially untrusted source"

View File

@@ -5,7 +5,7 @@
* @problem.severity error
* @security-severity 7.8
* @precision high
* @id cpp/user-controlled-file-decompression1
* @id cpp/user-controlled-file-zlibgz
* @tags security
* experimental
* external/cwe/cwe-409

View File

@@ -5,7 +5,7 @@
* @problem.severity error
* @security-severity 7.8
* @precision high
* @id cpp/user-controlled-file-decompression2
* @id cpp/user-controlled-file-zlibinflator
* @tags security
* experimental
* external/cwe/cwe-409
@@ -41,13 +41,6 @@ module ZlibTaintConfig implements DataFlow::ConfigSig {
fc.getArgument(0) = sink.asExpr()
)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc | fc.getTarget() instanceof InflateFunction |
node1.asExpr() = fc.getArgument(0) and
node2.asExpr() = fc
)
}
}
module ZlibTaint = TaintTracking::Global<ZlibTaintConfig>;

View File

@@ -5,7 +5,7 @@
* @problem.severity error
* @security-severity 7.8
* @precision high
* @id cpp/user-controlled-file-decompression3
* @id cpp/user-controlled-file-zlibuncompress
* @tags security
* experimental
* external/cwe/cwe-409
@@ -37,13 +37,6 @@ module ZlibTaintConfig implements DataFlow::ConfigSig {
fc.getArgument(0) = sink.asExpr()
)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc | fc.getTarget() instanceof UncompressFunction |
node1.asExpr() = fc.getArgument(0) and
node2.asExpr() = fc
)
}
}
module ZlibTaint = TaintTracking::Global<ZlibTaintConfig>;

View File

@@ -1,3 +1,8 @@
#include <iostream>
#include <vector>
#include "zlib.h"
#include <cstdio>
#include <cstring>
int UnsafeInflate(int argc, char *argv[]) {
// original string len = 36

View File

@@ -1,3 +1,8 @@
#include <iostream>
#include <vector>
#include "zlib.h"
#include <cstdio>
#include <cstring>
int SafeGzread() {
std::cout << "enter compressed file name!\n" << std::endl;