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:
Edward Minnix III
2023-05-04 20:14:22 -04:00
committed by GitHub
62 changed files with 1440 additions and 1076 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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)
}

View File

@@ -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>;

View File

@@ -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" }
}

View File

@@ -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()
)
}

View File

@@ -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>;

View 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>;

View File

@@ -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>;

View 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>;

View File

@@ -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
/**

View File

@@ -12,6 +12,7 @@
* external/cwe/cwe-088
*/
import java
import semmle.code.java.security.CommandLineQuery
import LocalUserInputToArgumentToExecFlow::PathGraph

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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
) {

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
)
}

View File

@@ -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

View File

@@ -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(),

View File

@@ -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

View File

@@ -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 = ""