Merge pull request #12829 from michaelnebel/csharp/refactordataflow4

C#: Re-factor tainttracking and dataflow configurations to use the new API.
This commit is contained in:
Michael Nebel
2023-04-19 08:32:36 +02:00
committed by GitHub
20 changed files with 235 additions and 128 deletions

View File

@@ -52,23 +52,24 @@ class IDbCommandConstructionSqlExpr extends SqlExpr, ObjectCreation {
class DapperCommandDefinitionMethodCallSqlExpr extends SqlExpr, ObjectCreation {
DapperCommandDefinitionMethodCallSqlExpr() {
this.getObjectType() instanceof Dapper::CommandDefinitionStruct and
exists(Conf c | c.hasFlow(DataFlow::exprNode(this), _))
DapperCommandDefinitionMethodCallSql::flow(DataFlow::exprNode(this), _)
}
override Expr getSql() { result = this.getArgumentForName("commandText") }
}
private class Conf extends DataFlow4::Configuration {
Conf() { this = "DapperCommandDefinitionFlowConfig" }
override predicate isSource(DataFlow::Node node) {
private module DapperCommandDefitionMethodCallSqlConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
node.asExpr().(ObjectCreation).getObjectType() instanceof Dapper::CommandDefinitionStruct
}
override predicate isSink(DataFlow::Node node) {
predicate isSink(DataFlow::Node node) {
exists(MethodCall mc |
mc.getTarget() = any(Dapper::SqlMapperClass c).getAQueryMethod() and
node.asExpr() = mc.getArgumentForName("command")
)
}
}
private module DapperCommandDefinitionMethodCallSql =
DataFlow::Global<DapperCommandDefitionMethodCallSqlConfig>;

View File

@@ -162,18 +162,14 @@ class XmlReaderSettingsCreation extends ObjectCreation {
}
}
private class SettingsDataFlowConfig extends DataFlow3::Configuration {
SettingsDataFlowConfig() { this = "SettingsDataFlowConfig" }
private module SettingsDataFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof XmlReaderSettingsCreation }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof XmlReaderSettingsCreation
}
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() instanceof XmlReaderSettingsInstance
}
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof XmlReaderSettingsInstance }
}
private module SettingsDataFlow = DataFlow::Global<SettingsDataFlowConfig>;
/** A call to `XmlReader.Create`. */
class XmlReaderCreateCall extends MethodCall {
XmlReaderCreateCall() { this.getTarget() = any(SystemXmlXmlReaderClass r).getCreateMethod() }
@@ -190,8 +186,6 @@ class XmlReaderSettingsInstance extends Expr {
/** Gets a possible creation point for this instance of `XmlReaderSettings`. */
XmlReaderSettingsCreation getASettingsCreation() {
exists(SettingsDataFlowConfig settingsFlow |
settingsFlow.hasFlow(DataFlow::exprNode(result), DataFlow::exprNode(this))
)
SettingsDataFlow::flow(DataFlow::exprNode(result), DataFlow::exprNode(this))
}
}

View File

@@ -78,10 +78,12 @@ predicate isExponentialRegex(StringLiteral s) {
}
/**
* DEPRECATED: Use `ExponentialRegexDataflow` instead.
*
* A data flow configuration for tracking exponential worst case time regular expression string
* literals to the pattern argument of a regex.
*/
class ExponentialRegexDataflow extends DataFlow2::Configuration {
deprecated class ExponentialRegexDataflow extends DataFlow2::Configuration {
ExponentialRegexDataflow() { this = "ExponentialRegex" }
override predicate isSource(DataFlow::Node s) { isExponentialRegex(s.asExpr()) }
@@ -89,15 +91,27 @@ class ExponentialRegexDataflow extends DataFlow2::Configuration {
override predicate isSink(DataFlow::Node s) { s.asExpr() = any(RegexOperation c).getPattern() }
}
/**
* A data flow configuration for tracking exponential worst case time regular expression string
* literals to the pattern argument of a regex.
*/
private module ExponentialRegexDataFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node s) { isExponentialRegex(s.asExpr()) }
predicate isSink(DataFlow::Node s) { s.asExpr() = any(RegexOperation c).getPattern() }
}
module ExponentialRegexDataFlow = DataFlow::Global<ExponentialRegexDataFlowConfig>;
/**
* An expression passed as the `input` to a call to a `Regex` method, where the regex appears to
* have exponential behavior.
*/
class ExponentialRegexSink extends DataFlow::ExprNode, Sink {
ExponentialRegexSink() {
exists(ExponentialRegexDataflow regexDataflow, RegexOperation regexOperation |
exists(RegexOperation regexOperation |
// Exponential regex flows to the pattern argument
regexDataflow.hasFlow(_, DataFlow::exprNode(regexOperation.getPattern()))
ExponentialRegexDataFlow::flow(_, DataFlow::exprNode(regexOperation.getPattern()))
|
// This is used as an input for this pattern
this.getExpr() = regexOperation.getInput() and

View File

@@ -75,9 +75,11 @@ class JsonConvertTrackingConfig extends TaintTracking::Configuration {
}
/**
* DEPRECATED: Use `TypeNameTracking` instead.
*
* Tracks unsafe `TypeNameHandling` setting to `JsonConvert` call
*/
class TypeNameTrackingConfig extends DataFlow::Configuration {
deprecated class TypeNameTrackingConfig extends DataFlow::Configuration {
TypeNameTrackingConfig() { this = "TypeNameTrackingConfig" }
override predicate isSource(DataFlow::Node source) {
@@ -127,6 +129,62 @@ class TypeNameTrackingConfig extends DataFlow::Configuration {
}
}
/**
* Configuration module for tracking unsafe `TypeNameHandling` setting to `JsonConvert` calls.
*/
private module TypeNameTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
(
source.asExpr() instanceof MemberConstantAccess and
source.getType() instanceof TypeNameHandlingEnum
or
source.asExpr() instanceof IntegerLiteral
) and
source.asExpr().hasValue() and
not source.asExpr().getValue() = "0"
}
predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc, Method m, Expr expr |
m = mc.getTarget() and
(
not mc.getArgument(0).hasValue() and
m instanceof NewtonsoftJsonConvertClassDeserializeObjectMethod
) and
expr = mc.getAnArgument() and
sink.asExpr() = expr and
expr.getType() instanceof JsonSerializerSettingsClass
)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
node1.asExpr() instanceof IntegerLiteral and
node2.asExpr().(CastExpr).getExpr() = node1.asExpr()
or
node1.getType() instanceof TypeNameHandlingEnum and
exists(PropertyWrite pw, Property p, Assignment a |
a.getLValue() = pw and
pw.getProperty() = p and
p.getDeclaringType() instanceof JsonSerializerSettingsClass and
p.hasName("TypeNameHandling") and
(
node1.asExpr() = a.getRValue() and
node2.asExpr() = pw.getQualifier()
or
exists(ObjectInitializer oi |
node1.asExpr() = oi.getAMemberInitializer().getRValue() and
node2.asExpr() = oi
)
)
)
}
}
/**
* Configuration module for tracking unsafe `TypeNameHandling` setting to `JsonConvert` calls.
*/
module TypeNameTracking = DataFlow::Global<TypeNameTrackingConfig>;
/**
* User input to static method or constructor call deserialization flow tracking.
*/

View File

@@ -172,26 +172,24 @@ module XmlReader {
isNetFrameworkBefore(this.(MethodCall).getTarget().getDeclaringType(), "4.0")
or
// bad settings flow here
exists(SettingsDataFlowConfig flow, ObjectCreation settings |
flow.hasFlow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
exists(ObjectCreation settings |
SettingsDataFlow::flow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
XmlSettings::dtdEnabledSettings(settings, evidence, reason)
)
}
private predicate insecureResolver(string reason, Expr evidence) {
// bad settings flow here
exists(SettingsDataFlowConfig flow, ObjectCreation settings |
flow.hasFlow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
exists(ObjectCreation settings |
SettingsDataFlow::flow(DataFlow::exprNode(settings), DataFlow::exprNode(this.getSettings())) and
XmlSettings::insecureResolverSettings(settings, evidence, reason)
)
// default is secure
}
}
private class SettingsDataFlowConfig extends DataFlow2::Configuration {
SettingsDataFlowConfig() { this = "SettingsDataFlowConfig" }
override predicate isSource(DataFlow::Node source) {
private module SettingsDataFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
// flow from places where we construct an XmlReaderSettings
source
.asExpr()
@@ -202,10 +200,12 @@ module XmlReader {
.hasQualifiedName("System.Xml", "XmlReaderSettings")
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(InsecureXmlReaderCreate create).getSettings()
}
}
private module SettingsDataFlow = DataFlow::Global<SettingsDataFlowConfig>;
}
/** Provides predicates related to `System.Xml.XmlTextReader`. */

View File

@@ -37,19 +37,19 @@ predicate inForeachStmtBody(ForeachStmt loop, Element e) {
)
}
class LambdaDataFlowConfiguration extends DataFlow::Configuration {
LambdaDataFlowConfiguration() { this = "LambdaDataFlowConfiguration" }
module LambdaDataFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { lambdaCapturesLoopVariable(source.asExpr(), _, _) }
override predicate isSource(DataFlow::Node source) {
lambdaCapturesLoopVariable(source.asExpr(), _, _)
}
predicate isSink(DataFlow::Node sink) { exists(getAssignmentTarget(sink.asExpr())) }
}
override predicate isSink(DataFlow::Node sink) { exists(getAssignmentTarget(sink.asExpr())) }
module LambdaDataFlow {
private import DataFlow::Global<LambdaDataFlowConfig>
predicate capturesLoopVarAndIsStoredIn(
AnonymousFunctionExpr lambda, Variable loopVar, Element storage
) {
exists(DataFlow::Node sink | this.hasFlow(DataFlow::exprNode(lambda), sink) |
exists(DataFlow::Node sink | flow(DataFlow::exprNode(lambda), sink) |
storage = getAssignmentTarget(sink.asExpr())
) and
exists(ForeachStmt loop | lambdaCapturesLoopVariable(lambda, loop, loopVar) |
@@ -109,7 +109,7 @@ predicate declaredInsideLoop(ForeachStmt loop, LocalVariable v) {
)
}
from LambdaDataFlowConfiguration c, AnonymousFunctionExpr lambda, Variable loopVar, Element storage
where c.capturesLoopVarAndIsStoredIn(lambda, loopVar, storage)
from AnonymousFunctionExpr lambda, Variable loopVar, Element storage
where LambdaDataFlow::capturesLoopVarAndIsStoredIn(lambda, loopVar, storage)
select lambda, "Function which may be stored in $@ captures variable $@.", storage,
storage.toString(), loopVar, loopVar.getName()

View File

@@ -12,12 +12,10 @@
import csharp
import semmle.code.csharp.dataflow.DataFlow::DataFlow
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import AddCertToRootStore::PathGraph
class AddCertToRootStoreConfig extends DataFlow::Configuration {
AddCertToRootStoreConfig() { this = "Adding Certificate To Root Store" }
override predicate isSource(DataFlow::Node source) {
module AddCertToRootStoreConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(ObjectCreation oc | oc = source.asExpr() |
oc.getType()
.(RefType)
@@ -26,7 +24,7 @@ class AddCertToRootStoreConfig extends DataFlow::Configuration {
)
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
(
mc.getTarget()
@@ -40,6 +38,8 @@ class AddCertToRootStoreConfig extends DataFlow::Configuration {
}
}
from DataFlow::PathNode oc, DataFlow::PathNode mc, AddCertToRootStoreConfig config
where config.hasFlowPath(oc, mc)
module AddCertToRootStore = DataFlow::Global<AddCertToRootStoreConfig>;
from AddCertToRootStore::PathNode oc, AddCertToRootStore::PathNode mc
where AddCertToRootStore::flowPath(oc, mc)
select mc.getNode(), oc, mc, "This certificate is added to the root certificate store."

View File

@@ -11,15 +11,13 @@
*/
import csharp
import DataFlow::PathGraph
import InsecureSqlConnection::PathGraph
/**
* A data flow configuration for tracking strings passed to `SqlConnection[StringBuilder]` instances.
*/
class TaintTrackingConfiguration extends DataFlow::Configuration {
TaintTrackingConfiguration() { this = "TaintTrackingConfiguration" }
override predicate isSource(DataFlow::Node source) {
module InsecureSqlConnectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(string s | s = source.asExpr().(StringLiteral).getValue().toLowerCase() |
s.matches("%encrypt=false%")
or
@@ -27,7 +25,7 @@ class TaintTrackingConfiguration extends DataFlow::Configuration {
)
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(ObjectCreation oc |
oc.getRuntimeArgument(0) = sink.asExpr() and
(
@@ -39,8 +37,13 @@ class TaintTrackingConfiguration extends DataFlow::Configuration {
}
}
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
/**
* A data flow configuration for tracking strings passed to `SqlConnection[StringBuilder]` instances.
*/
module InsecureSqlConnection = DataFlow::Global<InsecureSqlConnectionConfig>;
from InsecureSqlConnection::PathNode source, InsecureSqlConnection::PathNode sink
where InsecureSqlConnection::flowPath(source, sink)
select sink.getNode(), source, sink,
"$@ flows to this SQL connection and does not specify `Encrypt=True`.", source.getNode(),
"Connection string"

View File

@@ -48,12 +48,9 @@ where
)
or
// JsonConvert static method call, but with additional unsafe typename tracking
exists(
JsonConvertTrackingConfig taintTrackingJsonConvert, TypeNameTrackingConfig typenameTracking,
DataFlow::Node settingsCallArg
|
exists(JsonConvertTrackingConfig taintTrackingJsonConvert, DataFlow::Node settingsCallArg |
taintTrackingJsonConvert.hasFlowPath(userInput, deserializeCallArg) and
typenameTracking.hasFlow(_, settingsCallArg) and
TypeNameTracking::flow(_, settingsCallArg) and
deserializeCallArg.getNode().asExpr().getParent() = settingsCallArg.asExpr().getParent()
)
select deserializeCallArg, userInput, deserializeCallArg, "$@ flows to unsafe deserializer.",

View File

@@ -38,11 +38,8 @@ where
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
not exists(OnAppendCookieHttpOnlyTrackingConfig config | config.hasFlowTo(_)) and
// Passed as third argument to `IResponseCookies.Append`
exists(
CookieOptionsTrackingConfiguration cookieTracking, DataFlow::Node creation,
DataFlow::Node append
|
cookieTracking.hasFlow(creation, append) and
exists(DataFlow::Node creation, DataFlow::Node append |
CookieOptionsTracking::flow(creation, append) and
creation.asExpr() = oc and
append.asExpr() = mc.getArgument(2)
)
@@ -79,8 +76,8 @@ where
oc = c and
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
not isPropertySet(oc, "HttpOnly") and
exists(CookieOptionsTrackingConfiguration cookieTracking, DataFlow::Node creation |
cookieTracking.hasFlow(creation, _) and
exists(DataFlow::Node creation |
CookieOptionsTracking::flow(creation, _) and
creation.asExpr() = oc
)
)

View File

@@ -37,8 +37,8 @@ where
oc = c and
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
not isPropertySet(oc, "Secure") and
exists(CookieOptionsTrackingConfiguration cookieTracking, DataFlow::Node creation |
cookieTracking.hasFlow(creation, _) and
exists(DataFlow::Node creation |
CookieOptionsTracking::flow(creation, _) and
creation.asExpr() = oc
)
)
@@ -82,8 +82,8 @@ where
// there is no callback `OnAppendCookie` that sets `Secure` to true
not exists(OnAppendCookieSecureTrackingConfig config | config.hasFlowTo(_)) and
// the cookie option is passed to `Append`
exists(CookieOptionsTrackingConfiguration cookieTracking, DataFlow::Node creation |
cookieTracking.hasFlow(creation, _) and
exists(DataFlow::Node creation |
CookieOptionsTracking::flow(creation, _) and
creation.asExpr() = oc
)
)

View File

@@ -12,7 +12,7 @@
import csharp
import semmle.code.csharp.dataflow.DataFlow2
import semmle.code.csharp.dataflow.TaintTracking2
import DataFlow::PathGraph
import HashWithoutSalt::PathGraph
/** The C# class `Windows.Security.Cryptography.Core.HashAlgorithmProvider`. */
class HashAlgorithmProvider extends RefType {
@@ -120,12 +120,10 @@ predicate hasHashAncestor(MethodCall mc) {
* Taint configuration tracking flow from an expression whose name suggests it holds
* password data to a method call that generates a hash without a salt.
*/
class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
HashWithoutSaltConfiguration() { this = "HashWithoutSaltConfiguration" }
module HashWithoutSaltConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PasswordVarExpr }
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PasswordVarExpr }
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
sink.asExpr() = mc.getArgument(0) and
isHashCall(mc) and
@@ -148,7 +146,7 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
)
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodCall mc |
mc.getTarget()
.hasQualifiedName("Windows.Security.Cryptography", "CryptographicBuffer",
@@ -166,7 +164,7 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
* `byte[] saltedPassword = sha256.ComputeHash(rawSalted);`
* Or the password is concatenated with a salt as a string.
*/
override predicate isSanitizer(DataFlow::Node node) {
predicate isBarrier(DataFlow::Node node) {
exists(MethodCall mc |
hasFurtherProcessing(mc) and
mc.getAnArgument() = node.asExpr()
@@ -194,7 +192,9 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, HashWithoutSaltConfiguration c
where c.hasFlowPath(source, sink)
module HashWithoutSalt = TaintTracking::Global<HashWithoutSaltConfig>;
from HashWithoutSalt::PathNode source, HashWithoutSalt::PathNode sink
where HashWithoutSalt::flowPath(source, sink)
select sink.getNode(), source, sink, "$@ is hashed without a salt.", source.getNode(),
"The password"

View File

@@ -19,9 +19,11 @@ class TokenValidationParametersPropertySensitiveValidation extends Property {
}
/**
* DEPRECATED: Use `FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation` instead.
*
* A dataflow from a `false` value to a write sensitive property for `TokenValidationParameters`.
*/
class FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation extends DataFlow::Configuration
deprecated class FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation extends DataFlow::Configuration
{
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation() {
this = "FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation"
@@ -37,6 +39,25 @@ class FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation
}
}
/**
* A dataflow configuration from a `false` value to a write sensitive property for `TokenValidationParameters`.
*/
private module FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidationConfig
implements DataFlow::ConfigSig
{
predicate isSource(DataFlow::Node source) {
source.asExpr().getValue() = "false" and
source.asExpr().getType() instanceof BoolType
}
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(TokenValidationParametersPropertySensitiveValidation p).getAnAssignedValue()
}
}
module FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation =
DataFlow::Global<FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidationConfig>;
/**
* Holds if `assemblyName` is older than version `ver`
*/

View File

@@ -16,11 +16,10 @@ import JsonWebTokenHandlerLib
import semmle.code.csharp.commons.QualifiedName
from
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation config,
DataFlow::Node source, DataFlow::Node sink,
TokenValidationParametersPropertySensitiveValidation pw, string qualifier, string name
where
config.hasFlow(source, sink) and
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation::flow(source, sink) and
sink.asExpr() = pw.getAnAssignedValue() and
pw.hasQualifiedName(qualifier, name)
select sink, "The security sensitive property $@ is being disabled by the following value: $@.", pw,

View File

@@ -31,16 +31,16 @@ predicate unsafeDataContractTypeCreation(Expr e) {
e.(TypeofExpr).getTypeAccess().getTarget() instanceof DataSetOrTableRelatedClass
}
class Conf extends DataFlow::Configuration {
Conf() { this = "FlowToDataSerializerConstructor" }
module FlowToDataSerializerConstructorConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { unsafeDataContractTypeCreation(node.asExpr()) }
override predicate isSource(DataFlow::Node node) { unsafeDataContractTypeCreation(node.asExpr()) }
override predicate isSink(DataFlow::Node node) { xmlSerializerConstructorArgument(node.asExpr()) }
predicate isSink(DataFlow::Node node) { xmlSerializerConstructorArgument(node.asExpr()) }
}
from Conf conf, DataFlow::Node source, DataFlow::Node sink
where conf.hasFlow(source, sink)
module FlowToDataSerializerConstructor = DataFlow::Global<FlowToDataSerializerConstructorConfig>;
from DataFlow::Node source, DataFlow::Node sink
where FlowToDataSerializerConstructor::flow(source, sink)
select sink,
"Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source.",
source, source.toString()

View File

@@ -40,9 +40,11 @@ private class AuthCookieNameConfiguration extends DataFlow::Configuration {
}
/**
* DEPRECATED: Use `CookieOptionsTracking` instead.
*
* Tracks creation of `CookieOptions` to `IResponseCookies.Append(String, String, CookieOptions)` call as a third parameter.
*/
class CookieOptionsTrackingConfiguration extends DataFlow::Configuration {
deprecated class CookieOptionsTrackingConfiguration extends DataFlow::Configuration {
CookieOptionsTrackingConfiguration() { this = "CookieOptionsTrackingConfiguration" }
override predicate isSource(DataFlow::Node source) {
@@ -57,6 +59,29 @@ class CookieOptionsTrackingConfiguration extends DataFlow::Configuration {
}
}
/**
* Configuration module tracking creation of `CookieOptions` to `IResponseCookies.Append(String, String, CookieOptions)`
* calls as a third parameter.
*/
private module CookieOptionsTrackingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(ObjectCreation).getType() instanceof MicrosoftAspNetCoreHttpCookieOptions
}
predicate isSink(DataFlow::Node sink) {
exists(MicrosoftAspNetCoreHttpResponseCookies iResponse, MethodCall mc |
iResponse.getAppendMethod() = mc.getTarget() and
mc.getArgument(2) = sink.asExpr()
)
}
}
/**
* Tracking creation of `CookieOptions` to `IResponseCookies.Append(String, String, CookieOptions)`
* calls as a third parameter.
*/
module CookieOptionsTracking = DataFlow::Global<CookieOptionsTrackingConfig>;
/**
* Looks for property value of `CookiePolicyOptions` passed to `app.UseCookiePolicy` in `Startup.Configure`.
*/

View File

@@ -3,20 +3,18 @@
*/
import csharp
import DataFlow::PathGraph
import GlobalFlow::PathGraph
class DataflowConfiguration extends DataFlow::Configuration {
DataflowConfiguration() { this = "data flow configuration" }
module GlobalFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr().(Expr).getValue() = "tainted" }
override predicate isSource(DataFlow::Node source) {
source.asExpr().(Expr).getValue() = "tainted"
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(LocalVariable v | sink.asExpr() = v.getInitializer())
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, DataflowConfiguration conf
where conf.hasFlowPath(source, sink)
module GlobalFlow = DataFlow::Global<GlobalFlowConfig>;
from GlobalFlow::PathNode source, GlobalFlow::PathNode sink
where GlobalFlow::flowPath(source, sink)
select source, source, sink, "$@", sink, sink.toString()

View File

@@ -3,14 +3,12 @@
*/
import csharp
import DataFlow::PathGraph
import CallSensitivity::PathGraph
class Conf extends DataFlow::Configuration {
Conf() { this = "CallSensitiveFlowConf" }
module CallSensitivityConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ObjectCreation }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ObjectCreation }
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
mc.getTarget().hasName("Sink") and
mc.getAnArgument() = sink.asExpr()
@@ -18,6 +16,8 @@ class Conf extends DataFlow::Configuration {
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf
where conf.hasFlowPath(source, sink)
module CallSensitivity = DataFlow::Global<CallSensitivityConfig>;
from CallSensitivity::PathNode source, CallSensitivity::PathNode sink
where CallSensitivity::flowPath(source, sink)
select source, source, sink, "$@", sink, sink.toString()

View File

@@ -3,23 +3,23 @@
*/
import csharp
import DataFlow::PathGraph
import ArrayFlow::PathGraph
class Conf extends DataFlow::Configuration {
Conf() { this = "ArrayFlowConf" }
module ArrayFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ObjectCreation }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ObjectCreation }
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
mc.getTarget().hasUndecoratedName("Sink") and
mc.getAnArgument() = sink.asExpr()
)
}
override int fieldFlowBranchLimit() { result = 100 }
int fieldFlowBranchLimit() { result = 100 }
}
from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf
where conf.hasFlowPath(source, sink)
module ArrayFlow = DataFlow::Global<ArrayFlowConfig>;
from ArrayFlow::PathNode source, ArrayFlow::PathNode sink
where ArrayFlow::flowPath(source, sink)
select source, source, sink, "$@", sink, sink.toString()

View File

@@ -3,17 +3,15 @@
*/
import csharp
import DataFlow::PathGraph
import Types::PathGraph
class Conf extends DataFlow::Configuration {
Conf() { this = "TypesConf" }
override predicate isSource(DataFlow::Node src) {
module TypesConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) {
src.asExpr() instanceof ObjectCreation or
src.asExpr() instanceof NullLiteral
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(MethodCall mc |
mc.getTarget().hasUndecoratedName("Sink") and
mc.getAnArgument() = sink.asExpr()
@@ -21,6 +19,8 @@ class Conf extends DataFlow::Configuration {
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf
where conf.hasFlowPath(source, sink)
module Types = DataFlow::Global<TypesConfig>;
from Types::PathNode source, Types::PathNode sink
where Types::flowPath(source, sink)
select source, source, sink, "$@", sink, sink.toString()