mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
Merge pull request #12721 from egregius313/egregius313/java/move-configurations-to-libraries
Java: Move more dataflow configurations to `*Query.qll` files
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added the `ArithmeticCommon.qll` library to provide predicates for reasoning about arithmetic operations.
|
||||
* Added the `ArithmeticTaintedLocalQuery.qll` library to provide the `ArithmeticTaintedLocalOverflowFlow` and `ArithmeticTaintedLocalUnderflowFlow` taint-tracking modules to reason about arithmetic with unvalidated user input.
|
||||
* Added the `ArithmeticTaintedQuery.qll` library to provide the `RemoteUserInputOverflow` and `RemoteUserInputUnderflow` taint-tracking modules to reason about arithmetic with unvalidated user input.
|
||||
* Added the `ArithmeticUncontrolledQuery.qll` library to provide the `ArithmeticUncontrolledOverflowFlow` and `ArithmeticUncontrolledUnderflowFlow` taint-tracking modules to reason about arithmetic with uncontrolled user input.
|
||||
* Added the `ArithmeticWithExtremeValuesQuery.qll` library to provide the `MaxValueFlow` and `MinValueFlow` dataflow modules to reason about arithmetic with extreme values.
|
||||
* Added the `BrokenCryptoAlgorithmQuery.qll` library to provide the `InsecureCryptoFlow` taint-tracking module to reason about broken cryptographic algorithm vulnerabilities.
|
||||
* Added the `ExecTaintedLocalQuery.qll` library to provide the `LocalUserInputToArgumentToExecFlow` taint-tracking module to reason about command injection vulnerabilities caused by local data flow.
|
||||
* Added the `ExternallyControlledFormatStringLocalQuery.qll` library to provide the `ExternallyControlledFormatStringLocalFlow` taint-tracking module to reason about format string vulnerabilities caused by local data flow.
|
||||
* Added the `ImproperValidationOfArrayConstructionCodeSpecifiedQuery.qll` library to provide the `BoundedFlowSourceFlow` dataflow module to reason about improper validation of code-specified sizes used for array construction.
|
||||
* Added the `ImproperValidationOfArrayConstructionLocalQuery.qll` library to provide the `ImproperValidationOfArrayConstructionLocalFlow` taint-tracking module to reason about improper validation of local user-provided sizes used for array construction caused by local data flow.
|
||||
* Added the `ImproperValidationOfArrayConstructionQuery.qll` library to provide the `ImproperValidationOfArrayConstructionFlow` taint-tracking module to reason about improper validation of user-provided size used for array construction.
|
||||
* Added the `ImproperValidationOfArrayIndexCodeSpecifiedQuery.qll` library to provide the `BoundedFlowSourceFlow` data flow module to reason about about improper validation of code-specified array index.
|
||||
* Added the `ImproperValidationOfArrayIndexLocalQuery.qll` library to provide the `ImproperValidationOfArrayIndexLocalFlow` taint-tracking module to reason about improper validation of a local user-provided array index.
|
||||
* Added the `ImproperValidationOfArrayIndexQuery.qll` library to provide the `ImproperValidationOfArrayIndexFlow` taint-tracking module to reason about improper validation of user-provided array index.
|
||||
* Added the `InsecureCookieQuery.qll` library to provide the `SecureCookieFlow` taint-tracking module to reason about insecure cookie vulnerabilities.
|
||||
* Added the `MaybeBrokenCryptoAlgorithmQuery.qll` library to provide the `InsecureCryptoFlow` taint-tracking module to reason about broken cryptographic algorithm vulnerabilities.
|
||||
* Added the `NumericCastTaintedQuery.qll` library to provide the `NumericCastTaintedFlow` taint-tracking module to reason about numeric cast vulnerabilities.
|
||||
* Added the `ResponseSplittingLocalQuery.qll` library to provide the `ResponseSplittingLocalFlow` taint-tracking module to reason about response splitting vulnerabilities caused by local data flow.
|
||||
* Added the `SqlConcatenatedQuery.qll` library to provide the `UncontrolledStringBuilderSourceFlow` taint-tracking module to reason about SQL injection vulnerabilities caused by concatenating untrusted strings.
|
||||
* Added the `SqlTaintedLocalQuery.qll` library to provide the `LocalUserInputToArgumentToSqlFlow` taint-tracking module to reason about SQL injection vulnerabilities caused by local data flow.
|
||||
* Added the `StackTraceExposureQuery.qll` library to provide the `printsStackExternally`, `stringifiedStackFlowsExternally`, and `getMessageFlowsExternally` predicates to reason about stack trace exposure vulnerabilities.
|
||||
* Added the `TaintedPermissionQuery.qll` library to provide the `TaintedPermissionFlow` taint-tracking module to reason about tainted permission vulnerabilities.
|
||||
* Added the `TempDirLocalInformationDisclosureQuery.qll` library to provide the `TempDirSystemGetPropertyToCreate` taint-tracking module to reason about local information disclosure vulnerabilities caused by local data flow.
|
||||
* Added the `UnsafeHostnameVerificationQuery.qll` library to provide the `TrustAllHostnameVerifierFlow` taint-tracking module to reason about insecure hostname verification vulnerabilities.
|
||||
* Added the `UrlRedirectLocalQuery.qll` library to provide the `UrlRedirectLocalFlow` taint-tracking module to reason about URL redirection vulnerabilities caused by local data flow.
|
||||
* Added the `UrlRedirectQuery.qll` library to provide the `UrlRedirectFlow` taint-tracking module to reason about URL redirection vulnerabilities.
|
||||
* Added the `XPathInjectionQuery.qll` library to provide the `XPathInjectionFlow` taint-tracking module to reason about XPath injection vulnerabilities.
|
||||
* Added the `XssLocalQuery.qll` library to provide the `XssLocalFlow` taint-tracking module to reason about XSS vulnerabilities caused by local data flow.
|
||||
@@ -1,3 +1,5 @@
|
||||
/** Provides guards and predicates to reason about arithmetic. */
|
||||
|
||||
import semmle.code.java.arithmetic.Overflow
|
||||
import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.dataflow.SSA
|
||||
@@ -0,0 +1,39 @@
|
||||
/** Provides taint-tracking configurations to reason about arithmetic using local-user-controlled data. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.security.ArithmeticCommon
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration to reason about arithmetic overflow using local-user-controlled data.
|
||||
*/
|
||||
module ArithmeticTaintedLocalOverflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { overflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { overflowBarrier(n) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for arithmetic overflow using local-user-controlled data.
|
||||
*/
|
||||
module ArithmeticTaintedLocalOverflowFlow =
|
||||
TaintTracking::Global<ArithmeticTaintedLocalOverflowConfig>;
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration to reason about arithmetic underflow using local-user-controlled data.
|
||||
*/
|
||||
module ArithmeticTaintedLocalUnderflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { underflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { underflowBarrier(n) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for arithmetic underflow using local-user-controlled data.
|
||||
*/
|
||||
module ArithmeticTaintedLocalUnderflowFlow =
|
||||
TaintTracking::Global<ArithmeticTaintedLocalUnderflowConfig>;
|
||||
@@ -0,0 +1,29 @@
|
||||
/** Provides taint-tracking configurations to reason about arithmetic with unvalidated user input. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.security.ArithmeticCommon
|
||||
|
||||
/** A taint-tracking configuration to reason about overflow from unvalidated user input. */
|
||||
module RemoteUserInputOverflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { overflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { overflowBarrier(n) }
|
||||
}
|
||||
|
||||
/** A taint-tracking configuration to reason about underflow from unvalidated user input. */
|
||||
module RemoteUserInputUnderflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { underflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { underflowBarrier(n) }
|
||||
}
|
||||
|
||||
/** Taint-tracking flow for overflow from unvalidated user input. */
|
||||
module RemoteUserInputOverflow = TaintTracking::Global<RemoteUserInputOverflowConfig>;
|
||||
|
||||
/** Taint-tracking flow for underflow from unvalidated user input. */
|
||||
module RemoteUserInputUnderflow = TaintTracking::Global<RemoteUserInputUnderflowConfig>;
|
||||
@@ -0,0 +1,39 @@
|
||||
/** Provides taint-tracking configuration to reason about arithmetic with uncontrolled values. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.security.RandomQuery
|
||||
private import semmle.code.java.security.SecurityTests
|
||||
private import semmle.code.java.security.ArithmeticCommon
|
||||
|
||||
private class TaintSource extends DataFlow::ExprNode {
|
||||
TaintSource() {
|
||||
exists(RandomDataSource m | not m.resultMayBeBounded() | m.getOutput() = this.getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/** A taint-tracking configuration to reason about overflow from arithmetic with uncontrolled values. */
|
||||
module ArithmeticUncontrolledOverflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof TaintSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { overflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { overflowBarrier(n) }
|
||||
}
|
||||
|
||||
/** Taint-tracking flow to reason about overflow from arithmetic with uncontrolled values. */
|
||||
module ArithmeticUncontrolledOverflowFlow =
|
||||
TaintTracking::Global<ArithmeticUncontrolledOverflowConfig>;
|
||||
|
||||
/** A taint-tracking configuration to reason about underflow from arithmetic with uncontrolled values. */
|
||||
module ArithmeticUncontrolledUnderflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof TaintSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { underflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { underflowBarrier(n) }
|
||||
}
|
||||
|
||||
/** Taint-tracking flow to reason about underflow from arithmetic with uncontrolled values. */
|
||||
module ArithmeticUncontrolledUnderflowFlow =
|
||||
TaintTracking::Global<ArithmeticUncontrolledUnderflowConfig>;
|
||||
@@ -0,0 +1,61 @@
|
||||
/** Provides predicates and classes for reasoning about arithmetic with extreme values. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.security.ArithmeticCommon
|
||||
|
||||
/**
|
||||
* A field representing an extreme value.
|
||||
*
|
||||
* For example, `Integer.MAX_VALUE` or `Long.MIN_VALUE`.
|
||||
*/
|
||||
abstract class ExtremeValueField extends Field {
|
||||
ExtremeValueField() { this.getType() instanceof IntegralType }
|
||||
}
|
||||
|
||||
/** A field representing the minimum value of a primitive type. */
|
||||
private class MinValueField extends ExtremeValueField {
|
||||
MinValueField() { this.getName() = "MIN_VALUE" }
|
||||
}
|
||||
|
||||
/** A field representing the maximum value of a primitive type. */
|
||||
private class MaxValueField extends ExtremeValueField {
|
||||
MaxValueField() { this.getName() = "MAX_VALUE" }
|
||||
}
|
||||
|
||||
/** A variable access that refers to an extreme value. */
|
||||
class ExtremeSource extends VarAccess {
|
||||
ExtremeSource() { this.getVariable() instanceof ExtremeValueField }
|
||||
}
|
||||
|
||||
/** A dataflow configuration which tracks flow from maximum values to an overflow. */
|
||||
module MaxValueFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(ExtremeSource).getVariable() instanceof MaxValueField
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { overflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node n) { isSource(n) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { overflowBarrier(n) }
|
||||
}
|
||||
|
||||
/** Dataflow from maximum values to an underflow. */
|
||||
module MaxValueFlow = DataFlow::Global<MaxValueFlowConfig>;
|
||||
|
||||
/** A dataflow configuration which tracks flow from minimum values to an underflow. */
|
||||
module MinValueFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(ExtremeSource).getVariable() instanceof MinValueField
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { underflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node n) { isSource(n) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { underflowBarrier(n) }
|
||||
}
|
||||
|
||||
/** Dataflow from minimum values to an underflow. */
|
||||
module MinValueFlow = DataFlow::Global<MinValueFlowConfig>;
|
||||
@@ -0,0 +1,38 @@
|
||||
/** Provides to taint-tracking configuration to reason about the use of broken or risky cryptographic algorithms. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.security.Encryption
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
|
||||
private class ShortStringLiteral extends StringLiteral {
|
||||
ShortStringLiteral() { this.getValue().length() < 100 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A string literal that may refer to a broken or risky cryptographic algorithm.
|
||||
*/
|
||||
class BrokenAlgoLiteral extends ShortStringLiteral {
|
||||
BrokenAlgoLiteral() {
|
||||
this.getValue().regexpMatch(getInsecureAlgorithmRegex()) and
|
||||
// Exclude German and French sentences.
|
||||
not this.getValue().regexpMatch(".*\\p{IsLowercase} des \\p{IsLetter}.*")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration to reason about the use of broken or risky cryptographic algorithms.
|
||||
*/
|
||||
module InsecureCryptoConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof BrokenAlgoLiteral }
|
||||
|
||||
predicate isSink(DataFlow::Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for use of broken or risky cryptographic algorithms.
|
||||
*/
|
||||
module InsecureCryptoFlow = TaintTracking::Global<InsecureCryptoConfig>;
|
||||
@@ -0,0 +1,26 @@
|
||||
/** Provides a taint-tracking configuration to reason about use of externally controlled strings for command injection vulnerabilities. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.security.ExternalProcess
|
||||
private import semmle.code.java.security.CommandArguments
|
||||
|
||||
/** A taint-tracking configuration to reason about use of externally controlled strings to make command line commands. */
|
||||
module ExecTaintedLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof ArgumentToExec }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType
|
||||
or
|
||||
node.getType() instanceof BoxedType
|
||||
or
|
||||
isSafeCommandArgument(node.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for use of externally controlled strings to make command line commands.
|
||||
*/
|
||||
module ExecTaintedLocalFlow = TaintTracking::Global<ExecTaintedLocalConfig>;
|
||||
@@ -0,0 +1,20 @@
|
||||
/** Provides a taint-tracking configuration to reason about externally-controlled format strings from local sources. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.StringFormat
|
||||
|
||||
/** A taint-tracking configuration to reason about externally-controlled format strings from local sources. */
|
||||
module ExternallyControlledFormatStringLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(StringFormat formatCall).getFormatArgument()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for externally-controlled format strings from local sources.
|
||||
*/
|
||||
module ExternallyControlledFormatStringLocalFlow =
|
||||
TaintTracking::Global<ExternallyControlledFormatStringLocalConfig>;
|
||||
@@ -0,0 +1,25 @@
|
||||
/** Provides a dataflow configuration to reason about improper validation of code-specified size used for array construction. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.security.internal.ArraySizing
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
|
||||
/**
|
||||
* A dataflow configuration to reason about improper validation of code-specified size used for array construction.
|
||||
*/
|
||||
module BoundedFlowSourceConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof BoundedFlowSource and
|
||||
// There is not a fixed lower bound which is greater than zero.
|
||||
not source.(BoundedFlowSource).lowerBound() > 0
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CheckableArrayAccess caa).canThrowOutOfBoundsDueToEmptyArray(sink.asExpr(), _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dataflow flow for improper validation of code-specified size used for array construction.
|
||||
*/
|
||||
module BoundedFlowSourceFlow = DataFlow::Global<BoundedFlowSourceConfig>;
|
||||
@@ -0,0 +1,22 @@
|
||||
/** Provides a taint-tracking configuration to reason about improper validation of local user-provided size used for array construction. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.security.internal.ArraySizing
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration to reason about improper validation of local user-provided size used for array construction.
|
||||
*/
|
||||
module ImproperValidationOfArrayConstructionLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CheckableArrayAccess caa).canThrowOutOfBoundsDueToEmptyArray(sink.asExpr(), _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for improper validation of local user-provided size used for array construction.
|
||||
*/
|
||||
module ImproperValidationOfArrayConstructionLocalFlow =
|
||||
TaintTracking::Global<ImproperValidationOfArrayConstructionLocalConfig>;
|
||||
@@ -0,0 +1,22 @@
|
||||
/** Provides a taint-tracking configuration to reason about improper validation of user-provided size used for array construction. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.security.internal.ArraySizing
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration to reason about improper validation of user-provided size used for array construction.
|
||||
*/
|
||||
module ImproperValidationOfArrayConstructionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CheckableArrayAccess caa).canThrowOutOfBoundsDueToEmptyArray(sink.asExpr(), _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for improper validation of user-provided size used for array construction.
|
||||
*/
|
||||
module ImproperValidationOfArrayConstructionFlow =
|
||||
TaintTracking::Global<ImproperValidationOfArrayConstructionConfig>;
|
||||
@@ -0,0 +1,22 @@
|
||||
/** Provides a dataflow configuration to reason about improper validation of code-specified array index. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.security.internal.ArraySizing
|
||||
private import semmle.code.java.security.internal.BoundingChecks
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* A dataflow configuration to reason about improper validation of code-specified array index.
|
||||
*/
|
||||
module BoundedFlowSourceConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof BoundedFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(CheckableArrayAccess arrayAccess | arrayAccess.canThrowOutOfBounds(sink.asExpr()))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dataflow flow for improper validation of code-specified array index.
|
||||
*/
|
||||
module BoundedFlowSourceFlow = DataFlow::Global<BoundedFlowSourceConfig>;
|
||||
@@ -0,0 +1,22 @@
|
||||
/** Provides a taint-tracking configuration to reason about improper validation of local user-provided array index. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.security.internal.ArraySizing
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration to reason about improper validation of local user-provided array index.
|
||||
*/
|
||||
module ImproperValidationOfArrayIndexLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CheckableArrayAccess caa).canThrowOutOfBounds(sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for improper validation of local user-provided array index.
|
||||
*/
|
||||
module ImproperValidationOfArrayIndexLocalFlow =
|
||||
TaintTracking::Global<ImproperValidationOfArrayIndexLocalConfig>;
|
||||
@@ -0,0 +1,24 @@
|
||||
/** Provides a taint-tracking configuration to reason about improper validation of user-provided array index. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.security.internal.ArraySizing
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration to reason about improper validation of user-provided array index.
|
||||
*/
|
||||
module ImproperValidationOfArrayIndexConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CheckableArrayAccess caa).canThrowOutOfBounds(sink.asExpr())
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node.getType() instanceof BooleanType }
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for improper validation of user-provided array index.
|
||||
*/
|
||||
module ImproperValidationOfArrayIndexFlow =
|
||||
TaintTracking::Global<ImproperValidationOfArrayIndexConfig>;
|
||||
@@ -0,0 +1,41 @@
|
||||
/** Provides a dataflow configuration to reason about the failure to use secure cookies. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.frameworks.Servlets
|
||||
|
||||
private predicate isSafeSecureCookieSetting(Expr e) {
|
||||
e.(CompileTimeConstantExpr).getBooleanValue() = true
|
||||
or
|
||||
exists(Method isSecure |
|
||||
isSecure.hasName("isSecure") and
|
||||
isSecure.getDeclaringType().getASourceSupertype*() instanceof ServletRequest
|
||||
|
|
||||
e.(MethodAccess).getMethod() = isSecure
|
||||
)
|
||||
}
|
||||
|
||||
/** A dataflow configuration to reason about the failure to use secure cookies. */
|
||||
module SecureCookieConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
m.getDeclaringType() instanceof TypeCookie and
|
||||
m.getName() = "setSecure" and
|
||||
source.asExpr() = ma.getQualifier() and
|
||||
forex(DataFlow::Node argSource |
|
||||
DataFlow::localFlow(argSource, DataFlow::exprNode(ma.getArgument(0))) and
|
||||
not DataFlow::localFlowStep(_, argSource)
|
||||
|
|
||||
isSafeSecureCookieSetting(argSource.asExpr())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() =
|
||||
any(MethodAccess add | add.getMethod() instanceof ResponseAddCookieMethod).getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow to reason about the failure to use secure cookies. */
|
||||
module SecureCookieFlow = DataFlow::Global<SecureCookieConfig>;
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Provides classes and a taint-tracking configuration to reason about the use of potentially insecure cryptographic algorithms.
|
||||
*/
|
||||
|
||||
import java
|
||||
private import semmle.code.java.security.Encryption
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.dispatch.VirtualDispatch
|
||||
|
||||
private class ShortStringLiteral extends StringLiteral {
|
||||
ShortStringLiteral() { this.getValue().length() < 100 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A string literal that may refer to an insecure cryptographic algorithm.
|
||||
*/
|
||||
class InsecureAlgoLiteral extends ShortStringLiteral {
|
||||
InsecureAlgoLiteral() {
|
||||
// Algorithm identifiers should be at least two characters.
|
||||
this.getValue().length() > 1 and
|
||||
exists(string s | s = this.getValue() |
|
||||
not s.regexpMatch(getSecureAlgorithmRegex()) and
|
||||
// Exclude results covered by another query.
|
||||
not s.regexpMatch(getInsecureAlgorithmRegex())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate objectToString(MethodAccess ma) {
|
||||
exists(ToStringMethod m |
|
||||
m = ma.getMethod() and
|
||||
m.getDeclaringType() instanceof TypeObject and
|
||||
DataFlow::exprNode(ma.getQualifier()).getTypeBound().getErasure() instanceof TypeObject
|
||||
)
|
||||
}
|
||||
|
||||
private class StringContainer extends RefType {
|
||||
StringContainer() {
|
||||
this instanceof TypeString or
|
||||
this instanceof StringBuildingType or
|
||||
this.hasQualifiedName("java.util", "StringTokenizer") or
|
||||
this.(Array).getComponentType() instanceof StringContainer
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration to reason about the use of potentially insecure cryptographic algorithms.
|
||||
*/
|
||||
module InsecureCryptoConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof InsecureAlgoLiteral }
|
||||
|
||||
predicate isSink(DataFlow::Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) {
|
||||
objectToString(n.asExpr()) or
|
||||
not n.getType().getErasure() instanceof StringContainer
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for use of potentially insecure cryptographic algorithms.
|
||||
*/
|
||||
module InsecureCryptoFlow = TaintTracking::Global<InsecureCryptoConfig>;
|
||||
@@ -0,0 +1,133 @@
|
||||
/** Provides classes to reason about possible truncation from casting of a user-provided value. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.arithmetic.Overflow
|
||||
private import semmle.code.java.dataflow.SSA
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.dataflow.RangeAnalysis
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
/**
|
||||
* A `CastExpr` that is a narrowing cast.
|
||||
*/
|
||||
class NumericNarrowingCastExpr extends CastExpr {
|
||||
NumericNarrowingCastExpr() {
|
||||
exists(NumericType sourceType, NumericType targetType |
|
||||
sourceType = this.getExpr().getType() and targetType = this.getType()
|
||||
|
|
||||
not targetType.(NumType).widerThanOrEqualTo(sourceType)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that performs a right shift operation.
|
||||
*/
|
||||
class RightShiftOp extends Expr {
|
||||
RightShiftOp() {
|
||||
this instanceof RightShiftExpr or
|
||||
this instanceof UnsignedRightShiftExpr or
|
||||
this instanceof AssignRightShiftExpr or
|
||||
this instanceof AssignUnsignedRightShiftExpr
|
||||
}
|
||||
|
||||
private Expr getLhs() {
|
||||
this.(BinaryExpr).getLeftOperand() = result or
|
||||
this.(Assignment).getDest() = result
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variable that is shifted.
|
||||
*/
|
||||
Variable getShiftedVariable() {
|
||||
this.getLhs() = result.getAnAccess() or
|
||||
this.getLhs().(AndBitwiseExpr).getAnOperand() = result.getAnAccess()
|
||||
}
|
||||
}
|
||||
|
||||
private predicate boundedRead(RValue read) {
|
||||
exists(SsaVariable v, ConditionBlock cb, ComparisonExpr comp, boolean testIsTrue |
|
||||
read = v.getAUse() and
|
||||
cb.controls(read.getBasicBlock(), testIsTrue) and
|
||||
cb.getCondition() = comp
|
||||
|
|
||||
comp.getLesserOperand() = v.getAUse() and testIsTrue = true
|
||||
or
|
||||
comp.getGreaterOperand() = v.getAUse() and testIsTrue = false
|
||||
)
|
||||
}
|
||||
|
||||
private predicate castCheck(RValue read) {
|
||||
exists(EqualityTest eq, CastExpr cast |
|
||||
cast.getExpr() = read and
|
||||
eq.hasOperands(cast, read.getVariable().getAnAccess())
|
||||
)
|
||||
}
|
||||
|
||||
private class SmallType extends Type {
|
||||
SmallType() {
|
||||
this instanceof BooleanType or
|
||||
this.(PrimitiveType).hasName("byte") or
|
||||
this.(BoxedType).getPrimitiveType().hasName("byte")
|
||||
}
|
||||
}
|
||||
|
||||
private predicate smallExpr(Expr e) {
|
||||
exists(int low, int high |
|
||||
bounded(e, any(ZeroBound zb), low, false, _) and
|
||||
bounded(e, any(ZeroBound zb), high, true, _) and
|
||||
high - low < 256
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about user input that is used in a
|
||||
* numeric cast.
|
||||
*/
|
||||
module NumericCastFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr() and
|
||||
sink.asExpr() instanceof VarAccess
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
boundedRead(node.asExpr()) or
|
||||
castCheck(node.asExpr()) or
|
||||
node.getType() instanceof SmallType or
|
||||
smallExpr(node.asExpr()) or
|
||||
node.getEnclosingCallable() instanceof HashCodeMethod or
|
||||
exists(RightShiftOp e | e.getShiftedVariable().getAnAccess() = node.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for user input that is used in a numeric cast.
|
||||
*/
|
||||
module NumericCastFlow = TaintTracking::Global<NumericCastFlowConfig>;
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about local user input that is
|
||||
* used in a numeric cast.
|
||||
*/
|
||||
module NumericCastLocalFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr()
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
boundedRead(node.asExpr()) or
|
||||
castCheck(node.asExpr()) or
|
||||
node.getType() instanceof SmallType or
|
||||
smallExpr(node.asExpr()) or
|
||||
node.getEnclosingCallable() instanceof HashCodeMethod
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for local user input that is used in a numeric cast.
|
||||
*/
|
||||
module NumericCastLocalFlow = TaintTracking::Global<NumericCastLocalFlowConfig>;
|
||||
@@ -0,0 +1,24 @@
|
||||
/** Provides a taint-tracking configuration to reason about response splitting vulnerabilities from local user input. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.security.ResponseSplitting
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration to reason about response splitting vulnerabilities from local user input.
|
||||
*/
|
||||
module ResponseSplittingLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or
|
||||
node.getType() instanceof BoxedType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for response splitting vulnerabilities from local user input.
|
||||
*/
|
||||
module ResponseSplittingLocalFlow = TaintTracking::Global<ResponseSplittingLocalConfig>;
|
||||
@@ -0,0 +1,34 @@
|
||||
/** Provides classes and modules to reason about SqlInjection vulnerabilities from string concatentation. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.security.SqlConcatenatedLib
|
||||
private import semmle.code.java.security.SqlInjectionQuery
|
||||
|
||||
private class UncontrolledStringBuilderSource extends DataFlow::ExprNode {
|
||||
UncontrolledStringBuilderSource() {
|
||||
exists(StringBuilderVar sbv |
|
||||
uncontrolledStringBuilderQuery(sbv, _) and
|
||||
this.getExpr() = sbv.getToStringCall()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about uncontrolled string builders.
|
||||
*/
|
||||
module UncontrolledStringBuilderSourceFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof UncontrolledStringBuilderSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for uncontrolled string builders that are used in a SQL query.
|
||||
*/
|
||||
module UncontrolledStringBuilderSourceFlow =
|
||||
TaintTracking::Global<UncontrolledStringBuilderSourceFlowConfig>;
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for reasoning about local user input
|
||||
* that is used in a SQL query.
|
||||
*/
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.security.SqlInjectionQuery
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about local user input that is
|
||||
* used in a SQL query.
|
||||
*/
|
||||
module LocalUserInputToQueryInjectionFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(AdditionalQueryInjectionTaintStep s).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for local user input that is used in a SQL query.
|
||||
*/
|
||||
module LocalUserInputToQueryInjectionFlow =
|
||||
TaintTracking::Global<LocalUserInputToQueryInjectionFlowConfig>;
|
||||
@@ -0,0 +1,122 @@
|
||||
/** Provides predicates to reason about exposure of stack-traces. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.security.InformationLeak
|
||||
|
||||
/**
|
||||
* One of the `printStackTrace()` overloads on `Throwable`.
|
||||
*/
|
||||
private class PrintStackTraceMethod extends Method {
|
||||
PrintStackTraceMethod() {
|
||||
this.getDeclaringType()
|
||||
.getSourceDeclaration()
|
||||
.getASourceSupertype*()
|
||||
.hasQualifiedName("java.lang", "Throwable") and
|
||||
this.getName() = "printStackTrace"
|
||||
}
|
||||
}
|
||||
|
||||
private module ServletWriterSourceToPrintStackTraceMethodFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof XssVulnerableWriterSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
sink.asExpr() = ma.getAnArgument() and ma.getMethod() instanceof PrintStackTraceMethod
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module ServletWriterSourceToPrintStackTraceMethodFlow =
|
||||
TaintTracking::Global<ServletWriterSourceToPrintStackTraceMethodFlowConfig>;
|
||||
|
||||
/**
|
||||
* A call that uses `Throwable.printStackTrace()` on a stream that is connected
|
||||
* to external output.
|
||||
*/
|
||||
private predicate printsStackToWriter(MethodAccess call) {
|
||||
exists(PrintStackTraceMethod printStackTrace |
|
||||
call.getMethod() = printStackTrace and
|
||||
ServletWriterSourceToPrintStackTraceMethodFlow::flowToExpr(call.getAnArgument())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A `PrintWriter` that wraps a given string writer. This pattern is used
|
||||
* in the most common idiom for converting a `Throwable` to a string.
|
||||
*/
|
||||
private predicate printWriterOnStringWriter(Expr printWriter, Variable stringWriterVar) {
|
||||
printWriter.getType().(Class).hasQualifiedName("java.io", "PrintWriter") and
|
||||
stringWriterVar.getType().(Class).hasQualifiedName("java.io", "StringWriter") and
|
||||
(
|
||||
printWriter.(ClassInstanceExpr).getAnArgument() = stringWriterVar.getAnAccess() or
|
||||
printWriterOnStringWriter(printWriter.(VarAccess).getVariable().getInitializer(),
|
||||
stringWriterVar)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stackTraceExpr(Expr exception, MethodAccess stackTraceString) {
|
||||
exists(Expr printWriter, Variable stringWriterVar, MethodAccess printStackCall |
|
||||
printWriterOnStringWriter(printWriter, stringWriterVar) and
|
||||
printStackCall.getMethod() instanceof PrintStackTraceMethod and
|
||||
printStackCall.getAnArgument() = printWriter and
|
||||
printStackCall.getQualifier() = exception and
|
||||
stackTraceString.getQualifier() = stringWriterVar.getAnAccess() and
|
||||
stackTraceString.getMethod() instanceof ToStringMethod
|
||||
)
|
||||
}
|
||||
|
||||
private module StackTraceStringToHttpResponseSinkFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { stackTraceExpr(_, src.asExpr()) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink }
|
||||
}
|
||||
|
||||
private module StackTraceStringToHttpResponseSinkFlow =
|
||||
TaintTracking::Global<StackTraceStringToHttpResponseSinkFlowConfig>;
|
||||
|
||||
/**
|
||||
* Holds if `call` writes the data of `stackTrace` to an external stream.
|
||||
*/
|
||||
predicate printsStackExternally(MethodAccess call, Expr stackTrace) {
|
||||
printsStackToWriter(call) and
|
||||
call.getQualifier() = stackTrace and
|
||||
not call.getQualifier() instanceof SuperAccess
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `stackTrace` is a stringified stack trace which flows to an external sink.
|
||||
*/
|
||||
predicate stringifiedStackFlowsExternally(DataFlow::Node externalExpr, Expr stackTrace) {
|
||||
exists(MethodAccess stackTraceString |
|
||||
stackTraceExpr(stackTrace, stackTraceString) and
|
||||
StackTraceStringToHttpResponseSinkFlow::flow(DataFlow::exprNode(stackTraceString), externalExpr)
|
||||
)
|
||||
}
|
||||
|
||||
private class GetMessageFlowSource extends DataFlow::Node {
|
||||
GetMessageFlowSource() {
|
||||
exists(Method method | this.asExpr().(MethodAccess).getMethod() = method |
|
||||
method.hasName("getMessage") and
|
||||
method.hasNoParameters() and
|
||||
method.getDeclaringType().hasQualifiedName("java.lang", "Throwable")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module GetMessageFlowSourceToHttpResponseSinkFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof GetMessageFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink }
|
||||
}
|
||||
|
||||
private module GetMessageFlowSourceToHttpResponseSinkFlow =
|
||||
TaintTracking::Global<GetMessageFlowSourceToHttpResponseSinkFlowConfig>;
|
||||
|
||||
/**
|
||||
* Holds if there is a call to `getMessage()` that then flows to a servlet response.
|
||||
*/
|
||||
predicate getMessageFlowsExternally(DataFlow::Node externalExpr, GetMessageFlowSource getMessage) {
|
||||
GetMessageFlowSourceToHttpResponseSinkFlow::flow(getMessage, externalExpr)
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/** Provides classes to reason about tainted permissions check vulnerabilities. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
|
||||
/**
|
||||
* The `org.apache.shiro.subject.Subject` class.
|
||||
*/
|
||||
private class TypeShiroSubject extends RefType {
|
||||
TypeShiroSubject() { this.getQualifiedName() = "org.apache.shiro.subject.Subject" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `org.apache.shiro.authz.permission.WildcardPermission` class.
|
||||
*/
|
||||
private class TypeShiroWildCardPermission extends RefType {
|
||||
TypeShiroWildCardPermission() {
|
||||
this.getQualifiedName() = "org.apache.shiro.authz.permission.WildcardPermission"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that constructs a permission.
|
||||
*/
|
||||
abstract class PermissionsConstruction extends Top {
|
||||
/** Gets the input to this permission construction. */
|
||||
abstract Expr getInput();
|
||||
}
|
||||
|
||||
private class PermissionsCheckMethodAccess extends MethodAccess, PermissionsConstruction {
|
||||
PermissionsCheckMethodAccess() {
|
||||
exists(Method m | m = this.getMethod() |
|
||||
m.getDeclaringType() instanceof TypeShiroSubject and
|
||||
m.getName() = "isPermitted"
|
||||
or
|
||||
m.getName().toLowerCase().matches("%permitted%") and
|
||||
m.getNumberOfParameters() = 1
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getInput() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
private class WildCardPermissionConstruction extends ClassInstanceExpr, PermissionsConstruction {
|
||||
WildCardPermissionConstruction() {
|
||||
this.getConstructor().getDeclaringType() instanceof TypeShiroWildCardPermission
|
||||
}
|
||||
|
||||
override Expr getInput() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration for tracking flow from user input to a permissions check.
|
||||
*/
|
||||
module TaintedPermissionsCheckFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(PermissionsConstruction p).getInput()
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks flow from user input to a permissions check. */
|
||||
module TaintedPermissionsCheckFlow = TaintTracking::Global<TaintedPermissionsCheckFlowConfig>;
|
||||
@@ -0,0 +1,254 @@
|
||||
/** Provides classes to reason about local information disclosure in a temporary directory. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.os.OSCheck
|
||||
private import semmle.code.java.security.TempDirUtils
|
||||
|
||||
/**
|
||||
* A method which creates a file or directory in the file system.
|
||||
*/
|
||||
abstract private class MethodFileSystemFileCreation extends Method {
|
||||
MethodFileSystemFileCreation() { this.getDeclaringType() instanceof TypeFile }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method which creates a directory in the file system.
|
||||
*/
|
||||
private class MethodFileDirectoryCreation extends MethodFileSystemFileCreation {
|
||||
MethodFileDirectoryCreation() { this.hasName(["mkdir", "mkdirs"]) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method which creates a file in the file system.
|
||||
*/
|
||||
private class MethodFileFileCreation extends MethodFileSystemFileCreation {
|
||||
MethodFileFileCreation() { this.hasName("createNewFile") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A dataflow node that creates a file or directory in the file system.
|
||||
*/
|
||||
abstract private class FileCreationSink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* The qualifier of a call to one of `File`'s file-creating or directory-creating methods,
|
||||
* treated as a sink by `TempDirSystemGetPropertyToCreateConfig`.
|
||||
*/
|
||||
private class FileFileCreationSink extends FileCreationSink {
|
||||
FileFileCreationSink() {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof MethodFileSystemFileCreation and
|
||||
ma.getQualifier() = this.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The argument to a call to one of `Files` file-creating or directory-creating methods,
|
||||
* treated as a sink by `TempDirSystemGetPropertyToCreateConfig`.
|
||||
*/
|
||||
private class FilesFileCreationSink extends FileCreationSink {
|
||||
FilesFileCreationSink() {
|
||||
exists(FilesVulnerableCreationMethodAccess ma | ma.getArgument(0) = this.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a `Files` method that create files/directories without explicitly
|
||||
* setting the newly-created file or directory's permissions.
|
||||
*/
|
||||
private class FilesVulnerableCreationMethodAccess extends MethodAccess {
|
||||
FilesVulnerableCreationMethodAccess() {
|
||||
exists(Method m |
|
||||
m = this.getMethod() and
|
||||
m.getDeclaringType().hasQualifiedName("java.nio.file", "Files")
|
||||
|
|
||||
m.hasName(["write", "newBufferedWriter", "newOutputStream"])
|
||||
or
|
||||
m.hasName(["createFile", "createDirectory", "createDirectories"]) and
|
||||
this.getNumArgument() = 1
|
||||
or
|
||||
m.hasName("newByteChannel") and
|
||||
this.getNumArgument() = 2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a `File` method that create files/directories with a specific set of permissions explicitly set.
|
||||
* We can safely assume that any calls to these methods with explicit `PosixFilePermissions.asFileAttribute`
|
||||
* contains a certain level of intentionality behind it.
|
||||
*/
|
||||
private class FilesSanitizingCreationMethodAccess extends MethodAccess {
|
||||
FilesSanitizingCreationMethodAccess() {
|
||||
exists(Method m |
|
||||
m = this.getMethod() and
|
||||
m.getDeclaringType().hasQualifiedName("java.nio.file", "Files")
|
||||
|
|
||||
m.hasName(["createFile", "createDirectory", "createDirectories"]) and
|
||||
this.getNumArgument() = 2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The temp directory argument to a call to `java.io.File::createTempFile`,
|
||||
* treated as a sink by `TempDirSystemGetPropertyToCreateConfig`.
|
||||
*/
|
||||
private class FileCreateTempFileSink extends FileCreationSink {
|
||||
FileCreateTempFileSink() {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof MethodFileCreateTempFile and ma.getArgument(2) = this.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer that holds when the program is definitely running under some version of Windows.
|
||||
*/
|
||||
abstract private class WindowsOsSanitizer extends DataFlow::Node { }
|
||||
|
||||
private class IsNotUnixSanitizer extends WindowsOsSanitizer {
|
||||
IsNotUnixSanitizer() { any(IsUnixGuard guard).controls(this.asExpr().getBasicBlock(), false) }
|
||||
}
|
||||
|
||||
private class IsWindowsSanitizer extends WindowsOsSanitizer {
|
||||
IsWindowsSanitizer() { any(IsWindowsGuard guard).controls(this.asExpr().getBasicBlock(), true) }
|
||||
}
|
||||
|
||||
private class IsSpecificWindowsSanitizer extends WindowsOsSanitizer {
|
||||
IsSpecificWindowsSanitizer() {
|
||||
any(IsSpecificWindowsVariant guard).controls(this.asExpr().getBasicBlock(), true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint tracking configuration tracking the access of the system temporary directory
|
||||
* flowing to the creation of files or directories.
|
||||
*/
|
||||
module TempDirSystemGetPropertyToCreateConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof ExprSystemGetPropertyTempDirTainted
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof FileCreationSink and
|
||||
not TempDirSystemGetPropertyDirectlyToMkdir::flowTo(sink)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node sanitizer) {
|
||||
exists(FilesSanitizingCreationMethodAccess sanitisingMethodAccess |
|
||||
sanitizer.asExpr() = sanitisingMethodAccess.getArgument(0)
|
||||
)
|
||||
or
|
||||
sanitizer instanceof WindowsOsSanitizer
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow which tracks the access of the system temporary directory
|
||||
* flowing to the creation of files or directories.
|
||||
*/
|
||||
module TempDirSystemGetPropertyToCreate =
|
||||
TaintTracking::Global<TempDirSystemGetPropertyToCreateConfig>;
|
||||
|
||||
/**
|
||||
* Configuration that tracks calls to to `mkdir` or `mkdirs` that are are directly on the temp directory system property.
|
||||
* Examples:
|
||||
* - `File tempDir = new File(System.getProperty("java.io.tmpdir")); tempDir.mkdir();`
|
||||
* - `File tempDir = new File(System.getProperty("java.io.tmpdir")); tempDir.mkdirs();`
|
||||
*
|
||||
* These are examples of code that is simply verifying that the temp directory exists.
|
||||
* As such, this code pattern is filtered out as an explicit vulnerability in
|
||||
* `TempDirSystemGetPropertyToCreateConfig::isSink`.
|
||||
*/
|
||||
module TempDirSystemGetPropertyDirectlyToMkdirConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) {
|
||||
exists(ExprSystemGetPropertyTempDirTainted propertyGetExpr, DataFlow::Node callSite |
|
||||
DataFlow::localFlow(DataFlow::exprNode(propertyGetExpr), callSite)
|
||||
|
|
||||
isFileConstructorArgument(callSite.asExpr(), node.asExpr(), 1)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(MethodAccess ma | ma.getMethod() instanceof MethodFileDirectoryCreation |
|
||||
ma.getQualifier() = node.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node sanitizer) {
|
||||
isFileConstructorArgument(sanitizer.asExpr(), _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow that tracks calls to to `mkdir` or `mkdirs` that are are directly on the temp directory system property.
|
||||
* Examples:
|
||||
* - `File tempDir = new File(System.getProperty("java.io.tmpdir")); tempDir.mkdir();`
|
||||
* - `File tempDir = new File(System.getProperty("java.io.tmpdir")); tempDir.mkdirs();`
|
||||
*
|
||||
* These are examples of code that is simply verifying that the temp directory exists.
|
||||
* As such, this code pattern is filtered out as an explicit vulnerability in
|
||||
* `TempDirSystemGetPropertyToCreateConfig::isSink`.
|
||||
*/
|
||||
module TempDirSystemGetPropertyDirectlyToMkdir =
|
||||
TaintTracking::Global<TempDirSystemGetPropertyDirectlyToMkdirConfig>;
|
||||
|
||||
//
|
||||
// Begin configuration for tracking single-method calls that are vulnerable.
|
||||
//
|
||||
/**
|
||||
* A `MethodAccess` against a method that creates a temporary file or directory in a shared temporary directory.
|
||||
*/
|
||||
abstract class MethodAccessInsecureFileCreation extends MethodAccess {
|
||||
/**
|
||||
* Gets the type of entity created (e.g. `file`, `directory`, ...).
|
||||
*/
|
||||
abstract string getFileSystemEntityType();
|
||||
|
||||
/**
|
||||
* Gets the dataflow node representing the file system entity created.
|
||||
*/
|
||||
DataFlow::Node getNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* An insecure call to `java.io.File.createTempFile`.
|
||||
*/
|
||||
class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCreation {
|
||||
MethodAccessInsecureFileCreateTempFile() {
|
||||
this.getMethod() instanceof MethodFileCreateTempFile and
|
||||
(
|
||||
// `File.createTempFile(string, string)` always uses the default temporary directory
|
||||
this.getNumArgument() = 2
|
||||
or
|
||||
// The default temporary directory is used when the last argument of `File.createTempFile(string, string, File)` is `null`
|
||||
DataFlow::localExprFlow(any(NullLiteral n), this.getArgument(2))
|
||||
)
|
||||
}
|
||||
|
||||
override string getFileSystemEntityType() { result = "file" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `com.google.common.io.Files.createTempDir` method.
|
||||
*/
|
||||
class MethodGuavaFilesCreateTempFile extends Method {
|
||||
MethodGuavaFilesCreateTempFile() {
|
||||
this.getDeclaringType().hasQualifiedName("com.google.common.io", "Files") and
|
||||
this.hasName("createTempDir")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `com.google.common.io.Files.createTempDir` method.
|
||||
*/
|
||||
class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureFileCreation {
|
||||
MethodAccessInsecureGuavaFilesCreateTempFile() {
|
||||
this.getMethod() instanceof MethodGuavaFilesCreateTempFile
|
||||
}
|
||||
|
||||
override string getFileSystemEntityType() { result = "directory" }
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/** Provides predicates and dataflow configurations for reasoning about unsafe hostname verification. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.security.Encryption
|
||||
private import semmle.code.java.security.SecurityFlag
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
/**
|
||||
* Holds if `m` always returns `true` ignoring any exceptional flow.
|
||||
*/
|
||||
private predicate alwaysReturnsTrue(HostnameVerifierVerify m) {
|
||||
forex(ReturnStmt rs | rs.getEnclosingCallable() = m |
|
||||
rs.getResult().(CompileTimeConstantExpr).getBooleanValue() = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that overrides the `javax.net.ssl.HostnameVerifier.verify` method and **always** returns `true` (though it could also exit due to an uncaught exception), thus
|
||||
* accepting any certificate despite a hostname mismatch.
|
||||
*/
|
||||
class TrustAllHostnameVerifier extends RefType {
|
||||
TrustAllHostnameVerifier() {
|
||||
this.getAnAncestor() instanceof HostnameVerifier and
|
||||
exists(HostnameVerifierVerify m |
|
||||
m.getDeclaringType() = this and
|
||||
alwaysReturnsTrue(m)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration to model the flow of a `TrustAllHostnameVerifier` to a `set(Default)HostnameVerifier` call.
|
||||
*/
|
||||
module TrustAllHostnameVerifierConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(ClassInstanceExpr).getConstructedType() instanceof TrustAllHostnameVerifier
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof HostnameVerifierSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node barrier) {
|
||||
// ignore nodes that are in functions that intentionally disable hostname verification
|
||||
barrier
|
||||
.getEnclosingCallable()
|
||||
.getName()
|
||||
/*
|
||||
* Regex: (_)* :
|
||||
* some methods have underscores.
|
||||
* Regex: (no|ignore|disable)(strictssl|ssl|verify|verification|hostname)
|
||||
* noStrictSSL ignoreSsl
|
||||
* Regex: (set)?(accept|trust|ignore|allow)(all|every|any)
|
||||
* acceptAll trustAll ignoreAll setTrustAnyHttps
|
||||
* Regex: (use|do|enable)insecure
|
||||
* useInsecureSSL
|
||||
* Regex: (set|do|use)?no.*(check|validation|verify|verification)
|
||||
* setNoCertificateCheck
|
||||
* Regex: disable
|
||||
* disableChecks
|
||||
*/
|
||||
|
||||
.regexpMatch("^(?i)(_)*((no|ignore|disable)(strictssl|ssl|verify|verification|hostname)" +
|
||||
"|(set)?(accept|trust|ignore|allow)(all|every|any)" +
|
||||
"|(use|do|enable)insecure|(set|do|use)?no.*(check|validation|verify|verification)|disable).*$")
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow to model the flow of a `TrustAllHostnameVerifier` to a `set(Default)HostnameVerifier` call. */
|
||||
module TrustAllHostnameVerifierFlow = DataFlow::Global<TrustAllHostnameVerifierConfig>;
|
||||
|
||||
/**
|
||||
* A sink that sets the `HostnameVerifier` on `HttpsURLConnection`.
|
||||
*/
|
||||
private class HostnameVerifierSink extends DataFlow::Node {
|
||||
HostnameVerifierSink() { sinkNode(this, "set-hostname-verifier") }
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags suggesting a deliberately unsafe `HostnameVerifier` usage.
|
||||
*/
|
||||
private class UnsafeHostnameVerificationFlag extends FlagKind {
|
||||
UnsafeHostnameVerificationFlag() { this = "UnsafeHostnameVerificationFlag" }
|
||||
|
||||
bindingset[result]
|
||||
override string getAFlagName() {
|
||||
result
|
||||
.regexpMatch("(?i).*(secure|disable|selfCert|selfSign|validat|verif|trust|ignore|nocertificatecheck).*") and
|
||||
result != "equalsIgnoreCase"
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets a guard that represents a (likely) flag controlling an unsafe `HostnameVerifier` use. */
|
||||
private Guard getAnUnsafeHostnameVerifierFlagGuard() {
|
||||
result = any(UnsafeHostnameVerificationFlag flag).getAFlag().asExpr()
|
||||
}
|
||||
|
||||
/** Holds if `node` is guarded by a flag that suggests an intentionally insecure use. */
|
||||
predicate isNodeGuardedByFlag(DataFlow::Node node) {
|
||||
exists(Guard g | g.controls(node.asExpr().getBasicBlock(), _) |
|
||||
g = getASecurityFeatureFlagGuard() or g = getAnUnsafeHostnameVerifierFlagGuard()
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/** Provides a taint-tracking configuration to reason about URL redirection from local sources. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.security.UrlRedirect
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration to reason about URL redirection from local sources.
|
||||
*/
|
||||
module UrlRedirectLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof UrlRedirectSink }
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for URL redirection from local sources.
|
||||
*/
|
||||
module UrlRedirectLocalFlow = TaintTracking::Global<UrlRedirectLocalConfig>;
|
||||
19
java/ql/lib/semmle/code/java/security/UrlRedirectQuery.qll
Normal file
19
java/ql/lib/semmle/code/java/security/UrlRedirectQuery.qll
Normal file
@@ -0,0 +1,19 @@
|
||||
/** Provides a taint-tracking configuration for reasoning about URL redirections. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.security.UrlRedirect
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about URL redirections.
|
||||
*/
|
||||
module UrlRedirectConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof UrlRedirectSink }
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for URL redirections.
|
||||
*/
|
||||
module UrlRedirectFlow = TaintTracking::Global<UrlRedirectConfig>;
|
||||
@@ -0,0 +1,20 @@
|
||||
/** Provides taint-tracking flow to reason about XPath injection queries. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.security.XPath
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about XPath injection vulnerabilities.
|
||||
*/
|
||||
module XPathInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof XPathInjectionSink }
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for XPath injection vulnerabilities.
|
||||
*/
|
||||
module XPathInjectionFlow = TaintTracking::Global<XPathInjectionConfig>;
|
||||
20
java/ql/lib/semmle/code/java/security/XssLocalQuery.qll
Normal file
20
java/ql/lib/semmle/code/java/security/XssLocalQuery.qll
Normal file
@@ -0,0 +1,20 @@
|
||||
/** Provides a taint-tracking configuration to reason about cross-site scripting from a local source. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.security.XSS
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about cross-site scripting vulnerabilities from a local source.
|
||||
*/
|
||||
module XssLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for cross-site scripting vulnerabilities from a local source.
|
||||
*/
|
||||
module XssLocalFlow = TaintTracking::Global<XssLocalConfig>;
|
||||
@@ -1,7 +1,9 @@
|
||||
/** Provides predicates and classes to reason about the sizing and indexing of arrays. */
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.DefUse
|
||||
import semmle.code.java.security.RandomDataSource
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.DefUse
|
||||
private import semmle.code.java.security.RandomDataSource
|
||||
private import BoundingChecks
|
||||
|
||||
/**
|
||||
@@ -12,6 +12,7 @@
|
||||
* external/cwe/cwe-088
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.CommandLineQuery
|
||||
import LocalUserInputToArgumentToExecFlow::PathGraph
|
||||
|
||||
|
||||
@@ -12,17 +12,7 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.XSS
|
||||
|
||||
module XssLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
|
||||
}
|
||||
|
||||
module XssLocalFlow = TaintTracking::Global<XssLocalConfig>;
|
||||
|
||||
import semmle.code.java.security.XssLocalQuery
|
||||
import XssLocalFlow::PathGraph
|
||||
|
||||
from XssLocalFlow::PathNode source, XssLocalFlow::PathNode sink
|
||||
|
||||
@@ -15,28 +15,7 @@
|
||||
import java
|
||||
import semmle.code.java.security.SqlConcatenatedLib
|
||||
import semmle.code.java.security.SqlInjectionQuery
|
||||
|
||||
class UncontrolledStringBuilderSource extends DataFlow::ExprNode {
|
||||
UncontrolledStringBuilderSource() {
|
||||
exists(StringBuilderVar sbv |
|
||||
uncontrolledStringBuilderQuery(sbv, _) and
|
||||
this.getExpr() = sbv.getToStringCall()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module UncontrolledStringBuilderSourceFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof UncontrolledStringBuilderSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
}
|
||||
|
||||
module UncontrolledStringBuilderSourceFlow =
|
||||
TaintTracking::Global<UncontrolledStringBuilderSourceFlowConfig>;
|
||||
import semmle.code.java.security.SqlConcatenatedQuery
|
||||
|
||||
from QueryInjectionSink query, Expr uncontrolled
|
||||
where
|
||||
|
||||
@@ -12,27 +12,8 @@
|
||||
* external/cwe/cwe-564
|
||||
*/
|
||||
|
||||
import semmle.code.java.Expr
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.SqlInjectionQuery
|
||||
|
||||
module LocalUserInputToQueryInjectionFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(AdditionalQueryInjectionTaintStep s).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
module LocalUserInputToQueryInjectionFlow =
|
||||
TaintTracking::Global<LocalUserInputToQueryInjectionFlowConfig>;
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.SqlTaintedLocalQuery
|
||||
import LocalUserInputToQueryInjectionFlow::PathGraph
|
||||
|
||||
from
|
||||
|
||||
@@ -12,26 +12,11 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.ResponseSplitting
|
||||
import semmle.code.java.security.ResponseSplittingLocalQuery
|
||||
import ResponseSplittingLocalFlow::PathGraph
|
||||
|
||||
module ResponseSplittingLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or
|
||||
node.getType() instanceof BoxedType
|
||||
}
|
||||
}
|
||||
|
||||
module ResponseSplitting = TaintTracking::Global<ResponseSplittingLocalConfig>;
|
||||
|
||||
import ResponseSplitting::PathGraph
|
||||
|
||||
from ResponseSplitting::PathNode source, ResponseSplitting::PathNode sink
|
||||
where ResponseSplitting::flowPath(source, sink)
|
||||
from ResponseSplittingLocalFlow::PathNode source, ResponseSplittingLocalFlow::PathNode sink
|
||||
where ResponseSplittingLocalFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"This header depends on a $@, which may cause a response-splitting vulnerability.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -11,20 +11,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import ArraySizing
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
private module ImproperValidationOfArrayConstructionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CheckableArrayAccess caa).canThrowOutOfBoundsDueToEmptyArray(sink.asExpr(), _)
|
||||
}
|
||||
}
|
||||
|
||||
module ImproperValidationOfArrayConstructionFlow =
|
||||
TaintTracking::Global<ImproperValidationOfArrayConstructionConfig>;
|
||||
|
||||
import semmle.code.java.security.internal.ArraySizing
|
||||
import semmle.code.java.security.ImproperValidationOfArrayConstructionQuery
|
||||
import ImproperValidationOfArrayConstructionFlow::PathGraph
|
||||
|
||||
from
|
||||
|
||||
@@ -12,23 +12,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import ArraySizing
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
|
||||
module BoundedFlowSourceConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof BoundedFlowSource and
|
||||
// There is not a fixed lower bound which is greater than zero.
|
||||
not source.(BoundedFlowSource).lowerBound() > 0
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CheckableArrayAccess caa).canThrowOutOfBoundsDueToEmptyArray(sink.asExpr(), _)
|
||||
}
|
||||
}
|
||||
|
||||
module BoundedFlowSourceFlow = DataFlow::Global<BoundedFlowSourceConfig>;
|
||||
|
||||
import semmle.code.java.security.internal.ArraySizing
|
||||
import semmle.code.java.security.ImproperValidationOfArrayConstructionCodeSpecifiedQuery
|
||||
import BoundedFlowSourceFlow::PathGraph
|
||||
|
||||
from
|
||||
|
||||
@@ -12,20 +12,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import ArraySizing
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
module ImproperValidationOfArrayConstructionLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CheckableArrayAccess caa).canThrowOutOfBoundsDueToEmptyArray(sink.asExpr(), _)
|
||||
}
|
||||
}
|
||||
|
||||
module ImproperValidationOfArrayConstructionLocalFlow =
|
||||
TaintTracking::Global<ImproperValidationOfArrayConstructionLocalConfig>;
|
||||
|
||||
import semmle.code.java.security.internal.ArraySizing
|
||||
import semmle.code.java.security.ImproperValidationOfArrayConstructionLocalQuery
|
||||
import ImproperValidationOfArrayConstructionLocalFlow::PathGraph
|
||||
|
||||
from
|
||||
|
||||
@@ -11,22 +11,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import ArraySizing
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
module ImproperValidationOfArrayIndexConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CheckableArrayAccess caa).canThrowOutOfBounds(sink.asExpr())
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node.getType() instanceof BooleanType }
|
||||
}
|
||||
|
||||
module ImproperValidationOfArrayIndexFlow =
|
||||
TaintTracking::Global<ImproperValidationOfArrayIndexConfig>;
|
||||
|
||||
import semmle.code.java.security.internal.ArraySizing
|
||||
import semmle.code.java.security.ImproperValidationOfArrayIndexQuery
|
||||
import ImproperValidationOfArrayIndexFlow::PathGraph
|
||||
|
||||
from
|
||||
|
||||
@@ -12,20 +12,9 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import ArraySizing
|
||||
import BoundingChecks
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
|
||||
module BoundedFlowSourceConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof BoundedFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(CheckableArrayAccess arrayAccess | arrayAccess.canThrowOutOfBounds(sink.asExpr()))
|
||||
}
|
||||
}
|
||||
|
||||
module BoundedFlowSourceFlow = DataFlow::Global<BoundedFlowSourceConfig>;
|
||||
|
||||
import semmle.code.java.security.internal.ArraySizing
|
||||
import semmle.code.java.security.internal.BoundingChecks
|
||||
import semmle.code.java.security.ImproperValidationOfArrayIndexCodeSpecifiedQuery
|
||||
import BoundedFlowSourceFlow::PathGraph
|
||||
|
||||
from
|
||||
|
||||
@@ -12,20 +12,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import ArraySizing
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
module ImproperValidationOfArrayIndexLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CheckableArrayAccess caa).canThrowOutOfBounds(sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
module ImproperValidationOfArrayIndexLocalFlow =
|
||||
TaintTracking::Global<ImproperValidationOfArrayIndexLocalConfig>;
|
||||
|
||||
import semmle.code.java.security.internal.ArraySizing
|
||||
import semmle.code.java.security.ImproperValidationOfArrayIndexLocalQuery
|
||||
import ImproperValidationOfArrayIndexLocalFlow::PathGraph
|
||||
|
||||
from
|
||||
|
||||
@@ -11,20 +11,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.StringFormat
|
||||
|
||||
module ExternallyControlledFormatStringLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(StringFormat formatCall).getFormatArgument()
|
||||
}
|
||||
}
|
||||
|
||||
module ExternallyControlledFormatStringLocalFlow =
|
||||
TaintTracking::Global<ExternallyControlledFormatStringLocalConfig>;
|
||||
|
||||
import semmle.code.java.security.ExternallyControlledFormatStringLocalQuery
|
||||
import ExternallyControlledFormatStringLocalFlow::PathGraph
|
||||
|
||||
from
|
||||
|
||||
@@ -13,28 +13,9 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import ArithmeticCommon
|
||||
|
||||
module RemoteUserInputOverflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { overflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { overflowBarrier(n) }
|
||||
}
|
||||
|
||||
module RemoteUserInputUnderflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { underflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { underflowBarrier(n) }
|
||||
}
|
||||
|
||||
module RemoteUserInputOverflow = TaintTracking::Global<RemoteUserInputOverflowConfig>;
|
||||
|
||||
module RemoteUserInputUnderflow = TaintTracking::Global<RemoteUserInputUnderflowConfig>;
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.security.ArithmeticCommon
|
||||
import semmle.code.java.security.ArithmeticTaintedQuery
|
||||
|
||||
module Flow =
|
||||
DataFlow::MergePathGraph<RemoteUserInputOverflow::PathNode, RemoteUserInputUnderflow::PathNode,
|
||||
|
||||
@@ -13,30 +13,9 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import ArithmeticCommon
|
||||
|
||||
module ArithmeticTaintedLocalOverflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { overflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { overflowBarrier(n) }
|
||||
}
|
||||
|
||||
module ArithmeticTaintedLocalOverflowFlow =
|
||||
TaintTracking::Global<ArithmeticTaintedLocalOverflowConfig>;
|
||||
|
||||
module ArithmeticTaintedLocalUnderflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { underflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { underflowBarrier(n) }
|
||||
}
|
||||
|
||||
module ArithmeticTaintedLocalUnderflowFlow =
|
||||
TaintTracking::Global<ArithmeticTaintedLocalUnderflowConfig>;
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.security.ArithmeticCommon
|
||||
import semmle.code.java.security.ArithmeticTaintedLocalQuery
|
||||
|
||||
module Flow =
|
||||
DataFlow::MergePathGraph<ArithmeticTaintedLocalOverflowFlow::PathNode,
|
||||
|
||||
@@ -13,38 +13,9 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.RandomQuery
|
||||
import semmle.code.java.security.SecurityTests
|
||||
import ArithmeticCommon
|
||||
|
||||
class TaintSource extends DataFlow::ExprNode {
|
||||
TaintSource() {
|
||||
exists(RandomDataSource m | not m.resultMayBeBounded() | m.getOutput() = this.getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
module ArithmeticUncontrolledOverflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof TaintSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { overflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { overflowBarrier(n) }
|
||||
}
|
||||
|
||||
module ArithmeticUncontrolledOverflowFlow =
|
||||
TaintTracking::Global<ArithmeticUncontrolledOverflowConfig>;
|
||||
|
||||
module ArithmeticUncontrolledUnderflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof TaintSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { underflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { underflowBarrier(n) }
|
||||
}
|
||||
|
||||
module ArithmeticUncontrolledUnderflowFlow =
|
||||
TaintTracking::Global<ArithmeticUncontrolledUnderflowConfig>;
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.security.ArithmeticCommon
|
||||
import semmle.code.java.security.ArithmeticUncontrolledQuery
|
||||
|
||||
module Flow =
|
||||
DataFlow::MergePathGraph<ArithmeticUncontrolledOverflowFlow::PathNode,
|
||||
|
||||
@@ -15,58 +15,14 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import ArithmeticCommon
|
||||
|
||||
abstract class ExtremeValueField extends Field {
|
||||
ExtremeValueField() { this.getType() instanceof IntegralType }
|
||||
}
|
||||
|
||||
class MinValueField extends ExtremeValueField {
|
||||
MinValueField() { this.getName() = "MIN_VALUE" }
|
||||
}
|
||||
|
||||
class MaxValueField extends ExtremeValueField {
|
||||
MaxValueField() { this.getName() = "MAX_VALUE" }
|
||||
}
|
||||
|
||||
class ExtremeSource extends VarAccess {
|
||||
ExtremeSource() { this.getVariable() instanceof ExtremeValueField }
|
||||
}
|
||||
|
||||
module MaxValueFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(ExtremeSource).getVariable() instanceof MaxValueField
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { overflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node n) { isSource(n) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { overflowBarrier(n) }
|
||||
}
|
||||
|
||||
module MaxValueFlow = DataFlow::Global<MaxValueFlowConfig>;
|
||||
|
||||
module MinValueFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(ExtremeSource).getVariable() instanceof MinValueField
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { underflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node n) { isSource(n) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { underflowBarrier(n) }
|
||||
}
|
||||
|
||||
module MinValueFlow = DataFlow::Global<MinValueFlowConfig>;
|
||||
import semmle.code.java.security.ArithmeticCommon
|
||||
import semmle.code.java.security.ArithmeticWithExtremeValuesQuery
|
||||
import Flow::PathGraph
|
||||
|
||||
module Flow =
|
||||
DataFlow::MergePathGraph<MaxValueFlow::PathNode, MinValueFlow::PathNode, MaxValueFlow::PathGraph,
|
||||
MinValueFlow::PathGraph>;
|
||||
|
||||
import Flow::PathGraph
|
||||
|
||||
predicate query(
|
||||
Flow::PathNode source, Flow::PathNode sink, ArithExpr exp, string effect, Type srctyp
|
||||
) {
|
||||
|
||||
@@ -12,228 +12,9 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.os.OSCheck
|
||||
import TempDirUtils
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
|
||||
abstract private class MethodFileSystemFileCreation extends Method {
|
||||
MethodFileSystemFileCreation() { this.getDeclaringType() instanceof TypeFile }
|
||||
}
|
||||
|
||||
private class MethodFileDirectoryCreation extends MethodFileSystemFileCreation {
|
||||
MethodFileDirectoryCreation() { this.hasName(["mkdir", "mkdirs"]) }
|
||||
}
|
||||
|
||||
private class MethodFileFileCreation extends MethodFileSystemFileCreation {
|
||||
MethodFileFileCreation() { this.hasName("createNewFile") }
|
||||
}
|
||||
|
||||
abstract private class FileCreationSink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* The qualifier of a call to one of `File`'s file-creating or directory-creating methods,
|
||||
* treated as a sink by `TempDirSystemGetPropertyToCreateConfig`.
|
||||
*/
|
||||
private class FileFileCreationSink extends FileCreationSink {
|
||||
FileFileCreationSink() {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof MethodFileSystemFileCreation and
|
||||
ma.getQualifier() = this.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The argument to a call to one of `Files` file-creating or directory-creating methods,
|
||||
* treated as a sink by `TempDirSystemGetPropertyToCreateConfig`.
|
||||
*/
|
||||
private class FilesFileCreationSink extends FileCreationSink {
|
||||
FilesFileCreationSink() {
|
||||
exists(FilesVulnerableCreationMethodAccess ma | ma.getArgument(0) = this.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a `Files` method that create files/directories without explicitly
|
||||
* setting the newly-created file or directory's permissions.
|
||||
*/
|
||||
private class FilesVulnerableCreationMethodAccess extends MethodAccess {
|
||||
FilesVulnerableCreationMethodAccess() {
|
||||
exists(Method m |
|
||||
m = this.getMethod() and
|
||||
m.getDeclaringType().hasQualifiedName("java.nio.file", "Files")
|
||||
|
|
||||
m.hasName(["write", "newBufferedWriter", "newOutputStream"])
|
||||
or
|
||||
m.hasName(["createFile", "createDirectory", "createDirectories"]) and
|
||||
this.getNumArgument() = 1
|
||||
or
|
||||
m.hasName("newByteChannel") and
|
||||
this.getNumArgument() = 2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a `File` method that create files/directories with a specific set of permissions explicitly set.
|
||||
* We can safely assume that any calls to these methods with explicit `PosixFilePermissions.asFileAttribute`
|
||||
* contains a certain level of intentionality behind it.
|
||||
*/
|
||||
private class FilesSanitizingCreationMethodAccess extends MethodAccess {
|
||||
FilesSanitizingCreationMethodAccess() {
|
||||
exists(Method m |
|
||||
m = this.getMethod() and
|
||||
m.getDeclaringType().hasQualifiedName("java.nio.file", "Files")
|
||||
|
|
||||
m.hasName(["createFile", "createDirectory", "createDirectories"]) and
|
||||
this.getNumArgument() = 2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The temp directory argument to a call to `java.io.File::createTempFile`,
|
||||
* treated as a sink by `TempDirSystemGetPropertyToCreateConfig`.
|
||||
*/
|
||||
private class FileCreateTempFileSink extends FileCreationSink {
|
||||
FileCreateTempFileSink() {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof MethodFileCreateTempFile and ma.getArgument(2) = this.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer that holds when the program is definitely running under some version of Windows.
|
||||
*/
|
||||
abstract private class WindowsOsSanitizer extends DataFlow::Node { }
|
||||
|
||||
private class IsNotUnixSanitizer extends WindowsOsSanitizer {
|
||||
IsNotUnixSanitizer() { any(IsUnixGuard guard).controls(this.asExpr().getBasicBlock(), false) }
|
||||
}
|
||||
|
||||
private class IsWindowsSanitizer extends WindowsOsSanitizer {
|
||||
IsWindowsSanitizer() { any(IsWindowsGuard guard).controls(this.asExpr().getBasicBlock(), true) }
|
||||
}
|
||||
|
||||
private class IsSpecificWindowsSanitizer extends WindowsOsSanitizer {
|
||||
IsSpecificWindowsSanitizer() {
|
||||
any(IsSpecificWindowsVariant guard).controls(this.asExpr().getBasicBlock(), true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint tracking configuration tracking the access of the system temporary directory
|
||||
* flowing to the creation of files or directories.
|
||||
*/
|
||||
module TempDirSystemGetPropertyToCreateConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof ExprSystemGetPropertyTempDirTainted
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof FileCreationSink and
|
||||
not TempDirSystemGetPropertyDirectlyToMkdir::flowTo(sink)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node sanitizer) {
|
||||
exists(FilesSanitizingCreationMethodAccess sanitisingMethodAccess |
|
||||
sanitizer.asExpr() = sanitisingMethodAccess.getArgument(0)
|
||||
)
|
||||
or
|
||||
sanitizer instanceof WindowsOsSanitizer
|
||||
}
|
||||
}
|
||||
|
||||
module TempDirSystemGetPropertyToCreate =
|
||||
TaintTracking::Global<TempDirSystemGetPropertyToCreateConfig>;
|
||||
|
||||
/**
|
||||
* Configuration that tracks calls to to `mkdir` or `mkdirs` that are are directly on the temp directory system property.
|
||||
* Examples:
|
||||
* - `File tempDir = new File(System.getProperty("java.io.tmpdir")); tempDir.mkdir();`
|
||||
* - `File tempDir = new File(System.getProperty("java.io.tmpdir")); tempDir.mkdirs();`
|
||||
*
|
||||
* These are examples of code that is simply verifying that the temp directory exists.
|
||||
* As such, this code pattern is filtered out as an explicit vulnerability in
|
||||
* `TempDirSystemGetPropertyToCreateConfig::isSink`.
|
||||
*/
|
||||
module TempDirSystemGetPropertyDirectlyToMkdirConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) {
|
||||
exists(ExprSystemGetPropertyTempDirTainted propertyGetExpr, DataFlow::Node callSite |
|
||||
DataFlow::localFlow(DataFlow::exprNode(propertyGetExpr), callSite)
|
||||
|
|
||||
isFileConstructorArgument(callSite.asExpr(), node.asExpr(), 1)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(MethodAccess ma | ma.getMethod() instanceof MethodFileDirectoryCreation |
|
||||
ma.getQualifier() = node.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node sanitizer) {
|
||||
isFileConstructorArgument(sanitizer.asExpr(), _, _)
|
||||
}
|
||||
}
|
||||
|
||||
module TempDirSystemGetPropertyDirectlyToMkdir =
|
||||
TaintTracking::Global<TempDirSystemGetPropertyDirectlyToMkdirConfig>;
|
||||
|
||||
//
|
||||
// Begin configuration for tracking single-method calls that are vulnerable.
|
||||
//
|
||||
/**
|
||||
* A `MethodAccess` against a method that creates a temporary file or directory in a shared temporary directory.
|
||||
*/
|
||||
abstract class MethodAccessInsecureFileCreation extends MethodAccess {
|
||||
/**
|
||||
* Gets the type of entity created (e.g. `file`, `directory`, ...).
|
||||
*/
|
||||
abstract string getFileSystemEntityType();
|
||||
|
||||
DataFlow::Node getNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* An insecure call to `java.io.File.createTempFile`.
|
||||
*/
|
||||
class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCreation {
|
||||
MethodAccessInsecureFileCreateTempFile() {
|
||||
this.getMethod() instanceof MethodFileCreateTempFile and
|
||||
(
|
||||
// `File.createTempFile(string, string)` always uses the default temporary directory
|
||||
this.getNumArgument() = 2
|
||||
or
|
||||
// The default temporary directory is used when the last argument of `File.createTempFile(string, string, File)` is `null`
|
||||
DataFlow::localExprFlow(any(NullLiteral n), this.getArgument(2))
|
||||
)
|
||||
}
|
||||
|
||||
override string getFileSystemEntityType() { result = "file" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `com.google.common.io.Files.createTempDir` method.
|
||||
*/
|
||||
class MethodGuavaFilesCreateTempFile extends Method {
|
||||
MethodGuavaFilesCreateTempFile() {
|
||||
this.getDeclaringType().hasQualifiedName("com.google.common.io", "Files") and
|
||||
this.hasName("createTempDir")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `com.google.common.io.Files.createTempDir` method.
|
||||
*/
|
||||
class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureFileCreation {
|
||||
MethodAccessInsecureGuavaFilesCreateTempFile() {
|
||||
this.getMethod() instanceof MethodGuavaFilesCreateTempFile
|
||||
}
|
||||
|
||||
override string getFileSystemEntityType() { result = "directory" }
|
||||
}
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.security.TempDirUtils
|
||||
import semmle.code.java.security.TempDirLocalInformationDisclosureQuery
|
||||
|
||||
/**
|
||||
* We include use of inherently insecure methods, which don't have any associated
|
||||
|
||||
@@ -15,129 +15,11 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.InformationLeak
|
||||
|
||||
/**
|
||||
* One of the `printStackTrace()` overloads on `Throwable`.
|
||||
*/
|
||||
class PrintStackTraceMethod extends Method {
|
||||
PrintStackTraceMethod() {
|
||||
this.getDeclaringType()
|
||||
.getSourceDeclaration()
|
||||
.getASourceSupertype*()
|
||||
.hasQualifiedName("java.lang", "Throwable") and
|
||||
this.getName() = "printStackTrace"
|
||||
}
|
||||
}
|
||||
|
||||
module ServletWriterSourceToPrintStackTraceMethodFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof XssVulnerableWriterSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
sink.asExpr() = ma.getAnArgument() and ma.getMethod() instanceof PrintStackTraceMethod
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module ServletWriterSourceToPrintStackTraceMethodFlow =
|
||||
TaintTracking::Global<ServletWriterSourceToPrintStackTraceMethodFlowConfig>;
|
||||
|
||||
/**
|
||||
* A call that uses `Throwable.printStackTrace()` on a stream that is connected
|
||||
* to external output.
|
||||
*/
|
||||
predicate printsStackToWriter(MethodAccess call) {
|
||||
exists(PrintStackTraceMethod printStackTrace |
|
||||
call.getMethod() = printStackTrace and
|
||||
ServletWriterSourceToPrintStackTraceMethodFlow::flowToExpr(call.getAnArgument())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A `PrintWriter` that wraps a given string writer. This pattern is used
|
||||
* in the most common idiom for converting a `Throwable` to a string.
|
||||
*/
|
||||
predicate printWriterOnStringWriter(Expr printWriter, Variable stringWriterVar) {
|
||||
printWriter.getType().(Class).hasQualifiedName("java.io", "PrintWriter") and
|
||||
stringWriterVar.getType().(Class).hasQualifiedName("java.io", "StringWriter") and
|
||||
(
|
||||
printWriter.(ClassInstanceExpr).getAnArgument() = stringWriterVar.getAnAccess() or
|
||||
printWriterOnStringWriter(printWriter.(VarAccess).getVariable().getInitializer(),
|
||||
stringWriterVar)
|
||||
)
|
||||
}
|
||||
|
||||
predicate stackTraceExpr(Expr exception, MethodAccess stackTraceString) {
|
||||
exists(Expr printWriter, Variable stringWriterVar, MethodAccess printStackCall |
|
||||
printWriterOnStringWriter(printWriter, stringWriterVar) and
|
||||
printStackCall.getMethod() instanceof PrintStackTraceMethod and
|
||||
printStackCall.getAnArgument() = printWriter and
|
||||
printStackCall.getQualifier() = exception and
|
||||
stackTraceString.getQualifier() = stringWriterVar.getAnAccess() and
|
||||
stackTraceString.getMethod() instanceof ToStringMethod
|
||||
)
|
||||
}
|
||||
|
||||
module StackTraceStringToHttpResponseSinkFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { stackTraceExpr(_, src.asExpr()) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink }
|
||||
}
|
||||
|
||||
module StackTraceStringToHttpResponseSinkFlow =
|
||||
TaintTracking::Global<StackTraceStringToHttpResponseSinkFlowConfig>;
|
||||
|
||||
/**
|
||||
* A write of stack trace data to an external stream.
|
||||
*/
|
||||
predicate printsStackExternally(MethodAccess call, Expr stackTrace) {
|
||||
printsStackToWriter(call) and
|
||||
call.getQualifier() = stackTrace and
|
||||
not call.getQualifier() instanceof SuperAccess
|
||||
}
|
||||
|
||||
/**
|
||||
* A stringified stack trace flows to an external sink.
|
||||
*/
|
||||
predicate stringifiedStackFlowsExternally(DataFlow::Node externalExpr, Expr stackTrace) {
|
||||
exists(MethodAccess stackTraceString |
|
||||
stackTraceExpr(stackTrace, stackTraceString) and
|
||||
StackTraceStringToHttpResponseSinkFlow::flow(DataFlow::exprNode(stackTraceString), externalExpr)
|
||||
)
|
||||
}
|
||||
|
||||
class GetMessageFlowSource extends MethodAccess {
|
||||
GetMessageFlowSource() {
|
||||
exists(Method method |
|
||||
method = this.getMethod() and
|
||||
method.hasName("getMessage") and
|
||||
method.hasNoParameters() and
|
||||
method.getDeclaringType().hasQualifiedName("java.lang", "Throwable")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module GetMessageFlowSourceToHttpResponseSinkFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof GetMessageFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink }
|
||||
}
|
||||
|
||||
module GetMessageFlowSourceToHttpResponseSinkFlow =
|
||||
TaintTracking::Global<GetMessageFlowSourceToHttpResponseSinkFlowConfig>;
|
||||
|
||||
/**
|
||||
* A call to `getMessage()` that then flows to a servlet response.
|
||||
*/
|
||||
predicate getMessageFlowsExternally(DataFlow::Node externalExpr, GetMessageFlowSource getMessage) {
|
||||
GetMessageFlowSourceToHttpResponseSinkFlow::flow(DataFlow::exprNode(getMessage), externalExpr)
|
||||
}
|
||||
import semmle.code.java.security.StackTraceExposureQuery
|
||||
|
||||
from Expr externalExpr, Expr errorInformation
|
||||
where
|
||||
printsStackExternally(externalExpr, errorInformation) or
|
||||
stringifiedStackFlowsExternally(DataFlow::exprNode(externalExpr), errorInformation) or
|
||||
getMessageFlowsExternally(DataFlow::exprNode(externalExpr), errorInformation)
|
||||
getMessageFlowsExternally(DataFlow::exprNode(externalExpr), DataFlow::exprNode(errorInformation))
|
||||
select externalExpr, "$@ can be exposed to an external user.", errorInformation, "Error information"
|
||||
|
||||
@@ -11,109 +11,9 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.controlflow.Guards
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.Encryption
|
||||
import semmle.code.java.security.SecurityFlag
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
/**
|
||||
* Holds if `m` always returns `true` ignoring any exceptional flow.
|
||||
*/
|
||||
private predicate alwaysReturnsTrue(HostnameVerifierVerify m) {
|
||||
forex(ReturnStmt rs | rs.getEnclosingCallable() = m |
|
||||
rs.getResult().(CompileTimeConstantExpr).getBooleanValue() = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that overrides the `javax.net.ssl.HostnameVerifier.verify` method and **always** returns `true` (though it could also exit due to an uncaught exception), thus
|
||||
* accepting any certificate despite a hostname mismatch.
|
||||
*/
|
||||
class TrustAllHostnameVerifier extends RefType {
|
||||
TrustAllHostnameVerifier() {
|
||||
this.getAnAncestor() instanceof HostnameVerifier and
|
||||
exists(HostnameVerifierVerify m |
|
||||
m.getDeclaringType() = this and
|
||||
alwaysReturnsTrue(m)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration to model the flow of a `TrustAllHostnameVerifier` to a `set(Default)HostnameVerifier` call.
|
||||
*/
|
||||
module TrustAllHostnameVerifierConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(ClassInstanceExpr).getConstructedType() instanceof TrustAllHostnameVerifier
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof HostnameVerifierSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node barrier) {
|
||||
// ignore nodes that are in functions that intentionally disable hostname verification
|
||||
barrier
|
||||
.getEnclosingCallable()
|
||||
.getName()
|
||||
/*
|
||||
* Regex: (_)* :
|
||||
* some methods have underscores.
|
||||
* Regex: (no|ignore|disable)(strictssl|ssl|verify|verification|hostname)
|
||||
* noStrictSSL ignoreSsl
|
||||
* Regex: (set)?(accept|trust|ignore|allow)(all|every|any)
|
||||
* acceptAll trustAll ignoreAll setTrustAnyHttps
|
||||
* Regex: (use|do|enable)insecure
|
||||
* useInsecureSSL
|
||||
* Regex: (set|do|use)?no.*(check|validation|verify|verification)
|
||||
* setNoCertificateCheck
|
||||
* Regex: disable
|
||||
* disableChecks
|
||||
*/
|
||||
|
||||
.regexpMatch("^(?i)(_)*((no|ignore|disable)(strictssl|ssl|verify|verification|hostname)" +
|
||||
"|(set)?(accept|trust|ignore|allow)(all|every|any)" +
|
||||
"|(use|do|enable)insecure|(set|do|use)?no.*(check|validation|verify|verification)|disable).*$")
|
||||
}
|
||||
}
|
||||
|
||||
module TrustAllHostnameVerifierFlow = DataFlow::Global<TrustAllHostnameVerifierConfig>;
|
||||
|
||||
import semmle.code.java.security.UnsafeHostnameVerificationQuery
|
||||
import TrustAllHostnameVerifierFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A sink that sets the `HostnameVerifier` on `HttpsURLConnection`.
|
||||
*/
|
||||
private class HostnameVerifierSink extends DataFlow::Node {
|
||||
HostnameVerifierSink() { sinkNode(this, "set-hostname-verifier") }
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags suggesting a deliberately unsafe `HostnameVerifier` usage.
|
||||
*/
|
||||
private class UnsafeHostnameVerificationFlag extends FlagKind {
|
||||
UnsafeHostnameVerificationFlag() { this = "UnsafeHostnameVerificationFlag" }
|
||||
|
||||
bindingset[result]
|
||||
override string getAFlagName() {
|
||||
result
|
||||
.regexpMatch("(?i).*(secure|disable|selfCert|selfSign|validat|verif|trust|ignore|nocertificatecheck).*") and
|
||||
result != "equalsIgnoreCase"
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets a guard that represents a (likely) flag controlling an unsafe `HostnameVerifier` use. */
|
||||
private Guard getAnUnsafeHostnameVerifierFlagGuard() {
|
||||
result = any(UnsafeHostnameVerificationFlag flag).getAFlag().asExpr()
|
||||
}
|
||||
|
||||
/** Holds if `node` is guarded by a flag that suggests an intentionally insecure use. */
|
||||
private predicate isNodeGuardedByFlag(DataFlow::Node node) {
|
||||
exists(Guard g | g.controls(node.asExpr().getBasicBlock(), _) |
|
||||
g = getASecurityFeatureFlagGuard() or g = getAnUnsafeHostnameVerifierFlagGuard()
|
||||
)
|
||||
}
|
||||
|
||||
from
|
||||
TrustAllHostnameVerifierFlow::PathNode source, TrustAllHostnameVerifierFlow::PathNode sink,
|
||||
RefType verifier
|
||||
|
||||
@@ -13,41 +13,15 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.Encryption
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import DataFlow
|
||||
|
||||
private class ShortStringLiteral extends StringLiteral {
|
||||
ShortStringLiteral() { this.getValue().length() < 100 }
|
||||
}
|
||||
|
||||
class BrokenAlgoLiteral extends ShortStringLiteral {
|
||||
BrokenAlgoLiteral() {
|
||||
this.getValue().regexpMatch(getInsecureAlgorithmRegex()) and
|
||||
// Exclude German and French sentences.
|
||||
not this.getValue().regexpMatch(".*\\p{IsLowercase} des \\p{IsLetter}.*")
|
||||
}
|
||||
}
|
||||
|
||||
module InsecureCryptoConfig implements ConfigSig {
|
||||
predicate isSource(Node n) { n.asExpr() instanceof BrokenAlgoLiteral }
|
||||
|
||||
predicate isSink(Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
}
|
||||
|
||||
module InsecureCryptoFlow = TaintTracking::Global<InsecureCryptoConfig>;
|
||||
|
||||
import semmle.code.java.security.BrokenCryptoAlgorithmQuery
|
||||
import InsecureCryptoFlow::PathGraph
|
||||
|
||||
from
|
||||
InsecureCryptoFlow::PathNode source, InsecureCryptoFlow::PathNode sink, CryptoAlgoSpec c,
|
||||
BrokenAlgoLiteral s
|
||||
InsecureCryptoFlow::PathNode source, InsecureCryptoFlow::PathNode sink, CryptoAlgoSpec spec,
|
||||
BrokenAlgoLiteral algo
|
||||
where
|
||||
sink.getNode().asExpr() = c.getAlgoSpec() and
|
||||
source.getNode().asExpr() = s and
|
||||
sink.getNode().asExpr() = spec.getAlgoSpec() and
|
||||
source.getNode().asExpr() = algo and
|
||||
InsecureCryptoFlow::flowPath(source, sink)
|
||||
select c, source, sink, "Cryptographic algorithm $@ is weak and should not be used.", s,
|
||||
s.getValue()
|
||||
select spec, source, sink, "Cryptographic algorithm $@ is weak and should not be used.", algo,
|
||||
algo.getValue()
|
||||
|
||||
@@ -13,56 +13,7 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.Encryption
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import DataFlow
|
||||
import semmle.code.java.dispatch.VirtualDispatch
|
||||
|
||||
private class ShortStringLiteral extends StringLiteral {
|
||||
ShortStringLiteral() { this.getValue().length() < 100 }
|
||||
}
|
||||
|
||||
class InsecureAlgoLiteral extends ShortStringLiteral {
|
||||
InsecureAlgoLiteral() {
|
||||
// Algorithm identifiers should be at least two characters.
|
||||
this.getValue().length() > 1 and
|
||||
exists(string s | s = this.getValue() |
|
||||
not s.regexpMatch(getSecureAlgorithmRegex()) and
|
||||
// Exclude results covered by another query.
|
||||
not s.regexpMatch(getInsecureAlgorithmRegex())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate objectToString(MethodAccess ma) {
|
||||
exists(ToStringMethod m |
|
||||
m = ma.getMethod() and
|
||||
m.getDeclaringType() instanceof TypeObject and
|
||||
exprNode(ma.getQualifier()).getTypeBound().getErasure() instanceof TypeObject
|
||||
)
|
||||
}
|
||||
|
||||
class StringContainer extends RefType {
|
||||
StringContainer() {
|
||||
this instanceof TypeString or
|
||||
this instanceof StringBuildingType or
|
||||
this.hasQualifiedName("java.util", "StringTokenizer") or
|
||||
this.(Array).getComponentType() instanceof StringContainer
|
||||
}
|
||||
}
|
||||
|
||||
module InsecureCryptoConfig implements ConfigSig {
|
||||
predicate isSource(Node n) { n.asExpr() instanceof InsecureAlgoLiteral }
|
||||
|
||||
predicate isSink(Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) }
|
||||
|
||||
predicate isBarrier(Node n) {
|
||||
objectToString(n.asExpr()) or
|
||||
not n.getType().getErasure() instanceof StringContainer
|
||||
}
|
||||
}
|
||||
|
||||
module InsecureCryptoFlow = TaintTracking::Global<InsecureCryptoConfig>;
|
||||
|
||||
import semmle.code.java.security.MaybeBrokenCryptoAlgorithmQuery
|
||||
import InsecureCryptoFlow::PathGraph
|
||||
|
||||
from
|
||||
|
||||
@@ -12,17 +12,7 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.UrlRedirect
|
||||
|
||||
module UrlRedirectConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof UrlRedirectSink }
|
||||
}
|
||||
|
||||
module UrlRedirectFlow = TaintTracking::Global<UrlRedirectConfig>;
|
||||
|
||||
import semmle.code.java.security.UrlRedirectQuery
|
||||
import UrlRedirectFlow::PathGraph
|
||||
|
||||
from UrlRedirectFlow::PathNode source, UrlRedirectFlow::PathNode sink
|
||||
|
||||
@@ -12,17 +12,7 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.UrlRedirect
|
||||
|
||||
module UrlRedirectLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof UrlRedirectSink }
|
||||
}
|
||||
|
||||
module UrlRedirectLocalFlow = TaintTracking::Global<UrlRedirectLocalConfig>;
|
||||
|
||||
import semmle.code.java.security.UrlRedirectLocalQuery
|
||||
import UrlRedirectLocalFlow::PathGraph
|
||||
|
||||
from UrlRedirectLocalFlow::PathNode source, UrlRedirectLocalFlow::PathNode sink
|
||||
|
||||
@@ -13,41 +13,7 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.frameworks.Servlets
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
predicate isSafeSecureCookieSetting(Expr e) {
|
||||
e.(CompileTimeConstantExpr).getBooleanValue() = true
|
||||
or
|
||||
exists(Method isSecure |
|
||||
isSecure.getName() = "isSecure" and
|
||||
isSecure.getDeclaringType().getASourceSupertype*() instanceof ServletRequest
|
||||
|
|
||||
e.(MethodAccess).getMethod() = isSecure
|
||||
)
|
||||
}
|
||||
|
||||
module SecureCookieConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
m.getDeclaringType() instanceof TypeCookie and
|
||||
m.getName() = "setSecure" and
|
||||
source.asExpr() = ma.getQualifier() and
|
||||
forex(DataFlow::Node argSource |
|
||||
DataFlow::localFlow(argSource, DataFlow::exprNode(ma.getArgument(0))) and
|
||||
not DataFlow::localFlowStep(_, argSource)
|
||||
|
|
||||
isSafeSecureCookieSetting(argSource.asExpr())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() =
|
||||
any(MethodAccess add | add.getMethod() instanceof ResponseAddCookieMethod).getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
module SecureCookieFlow = DataFlow::Global<SecureCookieConfig>;
|
||||
import semmle.code.java.security.InsecureCookieQuery
|
||||
|
||||
from MethodAccess add
|
||||
where
|
||||
|
||||
@@ -12,18 +12,7 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.XPath
|
||||
|
||||
module XPathInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof XPathInjectionSink }
|
||||
}
|
||||
|
||||
module XPathInjectionFlow = TaintTracking::Global<XPathInjectionConfig>;
|
||||
|
||||
import semmle.code.java.security.XPathInjectionQuery
|
||||
import XPathInjectionFlow::PathGraph
|
||||
|
||||
from XPathInjectionFlow::PathNode source, XPathInjectionFlow::PathNode sink
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import java
|
||||
import semmle.code.java.arithmetic.Overflow
|
||||
import semmle.code.java.dataflow.SSA
|
||||
import semmle.code.java.controlflow.Guards
|
||||
import semmle.code.java.dataflow.RangeAnalysis
|
||||
|
||||
class NumericNarrowingCastExpr extends CastExpr {
|
||||
NumericNarrowingCastExpr() {
|
||||
exists(NumericType sourceType, NumericType targetType |
|
||||
sourceType = this.getExpr().getType() and targetType = this.getType()
|
||||
|
|
||||
not targetType.(NumType).widerThanOrEqualTo(sourceType)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class RightShiftOp extends Expr {
|
||||
RightShiftOp() {
|
||||
this instanceof RightShiftExpr or
|
||||
this instanceof UnsignedRightShiftExpr or
|
||||
this instanceof AssignRightShiftExpr or
|
||||
this instanceof AssignUnsignedRightShiftExpr
|
||||
}
|
||||
|
||||
private Expr getLhs() {
|
||||
this.(BinaryExpr).getLeftOperand() = result or
|
||||
this.(Assignment).getDest() = result
|
||||
}
|
||||
|
||||
Variable getShiftedVariable() {
|
||||
this.getLhs() = result.getAnAccess() or
|
||||
this.getLhs().(AndBitwiseExpr).getAnOperand() = result.getAnAccess()
|
||||
}
|
||||
}
|
||||
|
||||
predicate boundedRead(RValue read) {
|
||||
exists(SsaVariable v, ConditionBlock cb, ComparisonExpr comp, boolean testIsTrue |
|
||||
read = v.getAUse() and
|
||||
cb.controls(read.getBasicBlock(), testIsTrue) and
|
||||
cb.getCondition() = comp
|
||||
|
|
||||
comp.getLesserOperand() = v.getAUse() and testIsTrue = true
|
||||
or
|
||||
comp.getGreaterOperand() = v.getAUse() and testIsTrue = false
|
||||
)
|
||||
}
|
||||
|
||||
predicate castCheck(RValue read) {
|
||||
exists(EqualityTest eq, CastExpr cast |
|
||||
cast.getExpr() = read and
|
||||
eq.hasOperands(cast, read.getVariable().getAnAccess())
|
||||
)
|
||||
}
|
||||
|
||||
class SmallType extends Type {
|
||||
SmallType() {
|
||||
this instanceof BooleanType or
|
||||
this.(PrimitiveType).hasName("byte") or
|
||||
this.(BoxedType).getPrimitiveType().hasName("byte")
|
||||
}
|
||||
}
|
||||
|
||||
predicate smallExpr(Expr e) {
|
||||
exists(int low, int high |
|
||||
bounded(e, any(ZeroBound zb), low, false, _) and
|
||||
bounded(e, any(ZeroBound zb), high, true, _) and
|
||||
high - low < 256
|
||||
)
|
||||
}
|
||||
@@ -13,29 +13,7 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import NumericCastCommon
|
||||
|
||||
module NumericCastFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr() and
|
||||
sink.asExpr() instanceof VarAccess
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
boundedRead(node.asExpr()) or
|
||||
castCheck(node.asExpr()) or
|
||||
node.getType() instanceof SmallType or
|
||||
smallExpr(node.asExpr()) or
|
||||
node.getEnclosingCallable() instanceof HashCodeMethod or
|
||||
exists(RightShiftOp e | e.getShiftedVariable().getAnAccess() = node.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
module NumericCastFlow = TaintTracking::Global<NumericCastFlowConfig>;
|
||||
|
||||
import semmle.code.java.security.NumericCastTaintedQuery
|
||||
import NumericCastFlow::PathGraph
|
||||
|
||||
from NumericCastFlow::PathNode source, NumericCastFlow::PathNode sink, NumericNarrowingCastExpr exp
|
||||
|
||||
@@ -13,36 +13,16 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import NumericCastCommon
|
||||
|
||||
module NumericCastFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr()
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
boundedRead(node.asExpr()) or
|
||||
castCheck(node.asExpr()) or
|
||||
node.getType() instanceof SmallType or
|
||||
smallExpr(node.asExpr()) or
|
||||
node.getEnclosingCallable() instanceof HashCodeMethod
|
||||
}
|
||||
}
|
||||
|
||||
module NumericCastFlow = TaintTracking::Global<NumericCastFlowConfig>;
|
||||
|
||||
import NumericCastFlow::PathGraph
|
||||
import semmle.code.java.security.NumericCastTaintedQuery
|
||||
import NumericCastLocalFlow::PathGraph
|
||||
|
||||
from
|
||||
NumericCastFlow::PathNode source, NumericCastFlow::PathNode sink, NumericNarrowingCastExpr exp,
|
||||
VarAccess tainted
|
||||
NumericCastLocalFlow::PathNode source, NumericCastLocalFlow::PathNode sink,
|
||||
NumericNarrowingCastExpr exp, VarAccess tainted
|
||||
where
|
||||
exp.getExpr() = tainted and
|
||||
sink.getNode().asExpr() = tainted and
|
||||
NumericCastFlow::flowPath(source, sink) and
|
||||
NumericCastLocalFlow::flowPath(source, sink) and
|
||||
not exists(RightShiftOp e | e.getShiftedVariable() = tainted.getVariable())
|
||||
select exp, source, sink,
|
||||
"This cast to a narrower type depends on a $@, potentially causing truncation.", source.getNode(),
|
||||
|
||||
@@ -13,55 +13,7 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
|
||||
class TypeShiroSubject extends RefType {
|
||||
TypeShiroSubject() { this.getQualifiedName() = "org.apache.shiro.subject.Subject" }
|
||||
}
|
||||
|
||||
class TypeShiroWCPermission extends RefType {
|
||||
TypeShiroWCPermission() {
|
||||
this.getQualifiedName() = "org.apache.shiro.authz.permission.WildcardPermission"
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PermissionsConstruction extends Top {
|
||||
abstract Expr getInput();
|
||||
}
|
||||
|
||||
class PermissionsCheckMethodAccess extends MethodAccess, PermissionsConstruction {
|
||||
PermissionsCheckMethodAccess() {
|
||||
exists(Method m | m = this.getMethod() |
|
||||
m.getDeclaringType() instanceof TypeShiroSubject and
|
||||
m.getName() = "isPermitted"
|
||||
or
|
||||
m.getName().toLowerCase().matches("%permitted%") and
|
||||
m.getNumberOfParameters() = 1
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getInput() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
class WCPermissionConstruction extends ClassInstanceExpr, PermissionsConstruction {
|
||||
WCPermissionConstruction() {
|
||||
this.getConstructor().getDeclaringType() instanceof TypeShiroWCPermission
|
||||
}
|
||||
|
||||
override Expr getInput() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
module TaintedPermissionsCheckFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(PermissionsConstruction p).getInput()
|
||||
}
|
||||
}
|
||||
|
||||
module TaintedPermissionsCheckFlow = TaintTracking::Global<TaintedPermissionsCheckFlowConfig>;
|
||||
|
||||
import semmle.code.java.security.TaintedPermissionsCheckQuery
|
||||
import TaintedPermissionsCheckFlow::PathGraph
|
||||
|
||||
from
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.XPath
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.security.XPathInjectionQuery
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof XPathInjectionSink }
|
||||
}
|
||||
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
class HasXPathInjectionTest extends InlineExpectationsTest {
|
||||
HasXPathInjectionTest() { this = "HasXPathInjectionTest" }
|
||||
|
||||
@@ -19,7 +10,7 @@ class HasXPathInjectionTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasXPathInjection" and
|
||||
exists(DataFlow::Node sink | Flow::flowTo(sink) |
|
||||
exists(DataFlow::Node sink | XPathInjectionFlow::flowTo(sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
|
||||
Reference in New Issue
Block a user