mirror of
https://github.com/github/codeql.git
synced 2026-04-26 17:25:19 +02:00
Merge pull request #12808 from egregius313/egregius313/java/dataflow/refactor-experimental
Java: Refactor experimental queries to new DataFlow API
This commit is contained in:
@@ -16,9 +16,10 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
import DataFlow::PathGraph
|
||||
import Log4jInjectionFlow::PathGraph
|
||||
|
||||
private class ActivateModels extends ActiveExperimentalModels {
|
||||
ActivateModels() { this = "log4j-injection" }
|
||||
@@ -41,17 +42,20 @@ class Log4jInjectionSanitizer extends DataFlow::Node {
|
||||
/**
|
||||
* A taint-tracking configuration for tracking untrusted user input used in log entries.
|
||||
*/
|
||||
class Log4jInjectionConfiguration extends TaintTracking::Configuration {
|
||||
Log4jInjectionConfiguration() { this = "Log4jInjectionConfiguration" }
|
||||
module Log4jInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Log4jInjectionSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Log4jInjectionSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Log4jInjectionSanitizer }
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Log4jInjectionSanitizer }
|
||||
}
|
||||
|
||||
from Log4jInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
/**
|
||||
* Taint-tracking flow for tracking untrusted user input used in log entries.
|
||||
*/
|
||||
module Log4jInjectionFlow = TaintTracking::Global<Log4jInjectionConfig>;
|
||||
|
||||
from Log4jInjectionFlow::PathNode source, Log4jInjectionFlow::PathNode sink
|
||||
where Log4jInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Log4j log entry depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -15,7 +15,7 @@ import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
import DataFlow::PathGraph
|
||||
import RemoteUrlToOpenStreamFlow::PathGraph
|
||||
|
||||
class UrlConstructor extends ClassInstanceExpr {
|
||||
UrlConstructor() { this.getConstructor().getDeclaringType() instanceof TypeUrl }
|
||||
@@ -28,12 +28,10 @@ class UrlConstructor extends ClassInstanceExpr {
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteUrlToOpenStreamFlowConfig extends TaintTracking::Configuration {
|
||||
RemoteUrlToOpenStreamFlowConfig() { this = "OpenStream::RemoteURLToOpenStreamFlowConfig" }
|
||||
module RemoteUrlToOpenStreamFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess m |
|
||||
sink.asExpr() = m.getQualifier() and m.getMethod() instanceof UrlOpenStreamMethod
|
||||
)
|
||||
@@ -41,7 +39,7 @@ class RemoteUrlToOpenStreamFlowConfig extends TaintTracking::Configuration {
|
||||
sinkNode(sink, "url-open-stream")
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(UrlConstructor u |
|
||||
node1.asExpr() = u.stringArg() and
|
||||
node2.asExpr() = u
|
||||
@@ -49,9 +47,13 @@ class RemoteUrlToOpenStreamFlowConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, MethodAccess call
|
||||
module RemoteUrlToOpenStreamFlow = TaintTracking::Global<RemoteUrlToOpenStreamFlowConfig>;
|
||||
|
||||
from
|
||||
RemoteUrlToOpenStreamFlow::PathNode source, RemoteUrlToOpenStreamFlow::PathNode sink,
|
||||
MethodAccess call
|
||||
where
|
||||
sink.getNode().asExpr() = call.getQualifier() and
|
||||
any(RemoteUrlToOpenStreamFlowConfig c).hasFlowPath(source, sink)
|
||||
RemoteUrlToOpenStreamFlow::flowPath(source, sink)
|
||||
select call, source, sink,
|
||||
"URL on which openStream is called may have been constructed from remote source."
|
||||
|
||||
@@ -13,12 +13,13 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.PathCreation
|
||||
import JFinalController
|
||||
import semmle.code.java.security.PathSanitizer
|
||||
import DataFlow::PathGraph
|
||||
import InjectFilePathFlow::PathGraph
|
||||
|
||||
private class ActivateModels extends ActiveExperimentalModels {
|
||||
ActivateModels() { this = "file-path-injection" }
|
||||
@@ -47,24 +48,24 @@ class NormalizedPathNode extends DataFlow::Node {
|
||||
}
|
||||
}
|
||||
|
||||
class InjectFilePathConfig extends TaintTracking::Configuration {
|
||||
InjectFilePathConfig() { this = "InjectFilePathConfig" }
|
||||
module InjectFilePathConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(PathCreation p).getAnInput() and
|
||||
not sink instanceof NormalizedPathNode
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(Type t | t = node.getType() | t instanceof BoxedType or t instanceof PrimitiveType)
|
||||
or
|
||||
node instanceof PathInjectionSanitizer
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, InjectFilePathConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module InjectFilePathFlow = TaintTracking::Global<InjectFilePathConfig>;
|
||||
|
||||
from InjectFilePathFlow::PathNode source, InjectFilePathFlow::PathNode sink
|
||||
where InjectFilePathFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "External control of file name or path due to $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -13,27 +13,24 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import DataFlow::PathGraph
|
||||
import MyBatisCommonLib
|
||||
import MyBatisAnnotationSqlInjectionLib
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import MyBatisAnnotationSqlInjectionFlow::PathGraph
|
||||
|
||||
private class MyBatisAnnotationSqlInjectionConfiguration extends TaintTracking::Configuration {
|
||||
MyBatisAnnotationSqlInjectionConfiguration() { this = "MyBatis annotation sql injection" }
|
||||
private module MyBatisAnnotationSqlInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof MyBatisAnnotatedMethodCallArgument }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof MyBatisAnnotatedMethodCallArgument
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or
|
||||
node.getType() instanceof BoxedType or
|
||||
node.getType() instanceof NumberType
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod().getDeclaringType() instanceof TypeObject and
|
||||
ma.getMethod().getName() = "toString" and
|
||||
@@ -43,12 +40,15 @@ private class MyBatisAnnotationSqlInjectionConfiguration extends TaintTracking::
|
||||
}
|
||||
}
|
||||
|
||||
private module MyBatisAnnotationSqlInjectionFlow =
|
||||
TaintTracking::Global<MyBatisAnnotationSqlInjectionConfig>;
|
||||
|
||||
from
|
||||
MyBatisAnnotationSqlInjectionConfiguration cfg, DataFlow::PathNode source,
|
||||
DataFlow::PathNode sink, IbatisSqlOperationAnnotation isoa, MethodAccess ma,
|
||||
string unsafeExpression
|
||||
MyBatisAnnotationSqlInjectionFlow::PathNode source,
|
||||
MyBatisAnnotationSqlInjectionFlow::PathNode sink, IbatisSqlOperationAnnotation isoa,
|
||||
MethodAccess ma, string unsafeExpression
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
MyBatisAnnotationSqlInjectionFlow::flowPath(source, sink) and
|
||||
ma.getAnArgument() = sink.getNode().asExpr() and
|
||||
myBatisSqlOperationAnnotationFromMethod(ma.getMethod(), isoa) and
|
||||
unsafeExpression = getAMybatisAnnotationSqlValue(isoa) and
|
||||
|
||||
@@ -17,23 +17,23 @@ private predicate propertiesKey(DataFlow::Node prop, string key) {
|
||||
}
|
||||
|
||||
/** A data flow configuration tracing flow from ibatis `Configuration.getVariables()` to a store into a `Properties` object. */
|
||||
private class PropertiesFlowConfig extends DataFlow2::Configuration {
|
||||
PropertiesFlowConfig() { this = "PropertiesFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
private module PropertiesFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) {
|
||||
exists(MethodAccess ma | ma.getMethod() instanceof IbatisConfigurationGetVariablesMethod |
|
||||
src.asExpr() = ma
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { propertiesKey(sink, _) }
|
||||
predicate isSink(DataFlow::Node sink) { propertiesKey(sink, _) }
|
||||
}
|
||||
|
||||
private module PropertiesFlow = DataFlow::Global<PropertiesFlowConfig>;
|
||||
|
||||
/** Gets a `Properties` key that may map onto a Mybatis `Configuration` variable. */
|
||||
string getAMybatisConfigurationVariableKey() {
|
||||
exists(PropertiesFlowConfig conf, DataFlow::Node n |
|
||||
exists(DataFlow::Node n |
|
||||
propertiesKey(n, result) and
|
||||
conf.hasFlowTo(n)
|
||||
PropertiesFlow::flowTo(n)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,28 +13,24 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import DataFlow::PathGraph
|
||||
import MyBatisCommonLib
|
||||
import MyBatisMapperXmlSqlInjectionLib
|
||||
import semmle.code.xml.MyBatisMapperXML
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import MyBatisMapperXmlSqlInjectionFlow::PathGraph
|
||||
|
||||
private class MyBatisMapperXmlSqlInjectionConfiguration extends TaintTracking::Configuration {
|
||||
MyBatisMapperXmlSqlInjectionConfiguration() { this = "MyBatis mapper xml sql injection" }
|
||||
private module MyBatisMapperXmlSqlInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof MyBatisMapperMethodCallAnArgument }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof MyBatisMapperMethodCallAnArgument
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or
|
||||
node.getType() instanceof BoxedType or
|
||||
node.getType() instanceof NumberType
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod().getDeclaringType() instanceof TypeObject and
|
||||
ma.getMethod().getName() = "toString" and
|
||||
@@ -44,11 +40,15 @@ private class MyBatisMapperXmlSqlInjectionConfiguration extends TaintTracking::C
|
||||
}
|
||||
}
|
||||
|
||||
private module MyBatisMapperXmlSqlInjectionFlow =
|
||||
TaintTracking::Global<MyBatisMapperXmlSqlInjectionConfig>;
|
||||
|
||||
from
|
||||
MyBatisMapperXmlSqlInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||
MyBatisMapperXmlElement mmxe, MethodAccess ma, string unsafeExpression
|
||||
MyBatisMapperXmlSqlInjectionFlow::PathNode source,
|
||||
MyBatisMapperXmlSqlInjectionFlow::PathNode sink, MyBatisMapperXmlElement mmxe, MethodAccess ma,
|
||||
string unsafeExpression
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
MyBatisMapperXmlSqlInjectionFlow::flowPath(source, sink) and
|
||||
ma.getAnArgument() = sink.getNode().asExpr() and
|
||||
myBatisMapperXmlElementFromMethod(ma.getMethod(), mmxe) and
|
||||
unsafeExpression = getAMybatisXmlSetValue(mmxe) and
|
||||
|
||||
@@ -14,16 +14,15 @@
|
||||
import java
|
||||
import BeanShellInjection
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import BeanShellInjectionFlow::PathGraph
|
||||
|
||||
class BeanShellInjectionConfig extends TaintTracking::Configuration {
|
||||
BeanShellInjectionConfig() { this = "BeanShellInjectionConfig" }
|
||||
module BeanShellInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof BeanShellInjectionSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof BeanShellInjectionSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node prod, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node prod, DataFlow::Node succ) {
|
||||
exists(ClassInstanceExpr cie |
|
||||
cie.getConstructedType()
|
||||
.hasQualifiedName("org.springframework.scripting.support", "StaticScriptSource") and
|
||||
@@ -42,7 +41,9 @@ class BeanShellInjectionConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, BeanShellInjectionConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module BeanShellInjectionFlow = TaintTracking::Global<BeanShellInjectionConfig>;
|
||||
|
||||
from BeanShellInjectionFlow::PathNode source, BeanShellInjectionFlow::PathNode sink
|
||||
where BeanShellInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "BeanShell injection from $@.", source.getNode(),
|
||||
"this user input"
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import java
|
||||
import InsecureDexLoading
|
||||
import DataFlow::PathGraph
|
||||
import InsecureDexFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, InsecureDexConfiguration conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from InsecureDexFlow::PathNode source, InsecureDexFlow::PathNode sink
|
||||
where InsecureDexFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Potential arbitrary code execution due to $@.",
|
||||
source.getNode(), "a value loaded from a world-writable source."
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration detecting unsafe use of a
|
||||
* `DexClassLoader` by an Android app.
|
||||
*/
|
||||
class InsecureDexConfiguration extends TaintTracking::Configuration {
|
||||
InsecureDexConfiguration() { this = "Insecure Dex File Load" }
|
||||
module InsecureDexConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof InsecureDexSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof InsecureDexSource }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof InsecureDexSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof InsecureDexSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
flowStep(pred, succ)
|
||||
}
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { flowStep(pred, succ) }
|
||||
}
|
||||
|
||||
module InsecureDexFlow = TaintTracking::Global<InsecureDexConfig>;
|
||||
|
||||
/** A data flow source for insecure Dex class loading vulnerabilities. */
|
||||
abstract class InsecureDexSource extends DataFlow::Node { }
|
||||
|
||||
|
||||
@@ -14,16 +14,15 @@
|
||||
import java
|
||||
import JShellInjection
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import JShellInjectionFlow::PathGraph
|
||||
|
||||
class JShellInjectionConfiguration extends TaintTracking::Configuration {
|
||||
JShellInjectionConfiguration() { this = "JShellInjectionConfiguration" }
|
||||
module JShellInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof JShellInjectionSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof JShellInjectionSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(SourceCodeAnalysisAnalyzeCompletionCall scaacc |
|
||||
scaacc.getArgument(0) = pred.asExpr() and scaacc = succ.asExpr()
|
||||
)
|
||||
@@ -34,7 +33,9 @@ class JShellInjectionConfiguration extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, JShellInjectionConfiguration conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module JShellInjectionFlow = TaintTracking::Global<JShellInjectionConfig>;
|
||||
|
||||
from JShellInjectionFlow::PathNode source, JShellInjectionFlow::PathNode sink
|
||||
where JShellInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "JShell injection from $@.", source.getNode(),
|
||||
"this user input"
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import java
|
||||
import JakartaExpressionInjectionLib
|
||||
import DataFlow::PathGraph
|
||||
import JakartaExpressionInjectionFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, JakartaExpressionInjectionConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from JakartaExpressionInjectionFlow::PathNode source, JakartaExpressionInjectionFlow::PathNode sink
|
||||
where JakartaExpressionInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Jakarta Expression Language injection from $@.",
|
||||
source.getNode(), "this user input"
|
||||
|
||||
@@ -7,19 +7,22 @@ import semmle.code.java.dataflow.TaintTracking
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate an expression.
|
||||
*/
|
||||
class JakartaExpressionInjectionConfig extends TaintTracking::Configuration {
|
||||
JakartaExpressionInjectionConfig() { this = "JakartaExpressionInjectionConfig" }
|
||||
module JakartaExpressionInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof ExpressionEvaluationSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ExpressionEvaluationSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
any(TaintPropagatingCall c).taintFlow(fromNode, toNode) or
|
||||
hasGetterFlow(fromNode, toNode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow from remote sources, through an expression, to its eventual evaluation.
|
||||
*/
|
||||
module JakartaExpressionInjectionFlow = TaintTracking::Global<JakartaExpressionInjectionConfig>;
|
||||
|
||||
/**
|
||||
* A sink for Expresssion Language injection vulnerabilities,
|
||||
* i.e. method calls that run evaluation of an expression.
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.frameworks.spring.SpringController
|
||||
import DataFlow::PathGraph
|
||||
import CodeInjectionFlow::PathGraph
|
||||
|
||||
/** The class `org.python.util.PythonInterpreter`. */
|
||||
class PythonInterpreter extends RefType {
|
||||
@@ -101,15 +102,19 @@ class CodeInjectionSink extends DataFlow::ExprNode {
|
||||
* A taint configuration for tracking flow from `RemoteFlowSource` to a Jython method call
|
||||
* `CodeInjectionSink` that executes injected code.
|
||||
*/
|
||||
class CodeInjectionConfiguration extends TaintTracking::Configuration {
|
||||
CodeInjectionConfiguration() { this = "CodeInjectionConfiguration" }
|
||||
module CodeInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof CodeInjectionSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof CodeInjectionSink }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, CodeInjectionConfiguration conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
/**
|
||||
* Taint tracking flow from `RemoteFlowSource` to a Jython method call
|
||||
* `CodeInjectionSink` that executes injected code.
|
||||
*/
|
||||
module CodeInjectionFlow = TaintTracking::Global<CodeInjectionConfig>;
|
||||
|
||||
from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink
|
||||
where CodeInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode().(CodeInjectionSink).getMethodAccess(), source, sink, "Jython evaluate $@.",
|
||||
source.getNode(), "user input"
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
import ScriptInjectionFlow::PathGraph
|
||||
|
||||
/** A method of ScriptEngine that allows code injection. */
|
||||
class ScriptEngineMethod extends Method {
|
||||
@@ -133,15 +134,15 @@ class ScriptInjectionSink extends DataFlow::ExprNode {
|
||||
* A taint tracking configuration that tracks flow from `RemoteFlowSource` to an argument
|
||||
* of a method call that executes injected script.
|
||||
*/
|
||||
class ScriptInjectionConfiguration extends TaintTracking::Configuration {
|
||||
ScriptInjectionConfiguration() { this = "ScriptInjectionConfiguration" }
|
||||
module ScriptInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ScriptInjectionSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof ScriptInjectionSink }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, ScriptInjectionConfiguration conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module ScriptInjectionFlow = TaintTracking::Global<ScriptInjectionConfig>;
|
||||
|
||||
from ScriptInjectionFlow::PathNode source, ScriptInjectionFlow::PathNode sink
|
||||
where ScriptInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode().(ScriptInjectionSink).getMethodAccess(), source, sink,
|
||||
"Java Script Engine evaluate $@.", source.getNode(), "user input"
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
|
||||
import java
|
||||
import SpringViewManipulationLib
|
||||
import DataFlow::PathGraph
|
||||
import SpringViewManipulationFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, SpringViewManipulationConfig conf
|
||||
from SpringViewManipulationFlow::PathNode source, SpringViewManipulationFlow::PathNode sink
|
||||
where
|
||||
thymeleafIsUsed() and
|
||||
conf.hasFlowPath(source, sink)
|
||||
SpringViewManipulationFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Potential Spring Expression Language injection from $@.",
|
||||
source.getNode(), "this user input"
|
||||
|
||||
@@ -40,18 +40,16 @@ class PortletRenderRequestMethod extends Method {
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that can lead to Spring View Manipulation vulnerabilities.
|
||||
*/
|
||||
class SpringViewManipulationConfig extends TaintTracking::Configuration {
|
||||
SpringViewManipulationConfig() { this = "Spring View Manipulation Config" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module SpringViewManipulationConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof RemoteFlowSource or
|
||||
source instanceof WebRequestSource or
|
||||
source.asExpr().(MethodAccess).getMethod() instanceof PortletRenderRequestMethod
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof SpringViewManipulationSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof SpringViewManipulationSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
// Block flows like
|
||||
// ```
|
||||
// a = "redirect:" + taint`
|
||||
@@ -88,6 +86,8 @@ class SpringViewManipulationConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
module SpringViewManipulationFlow = TaintTracking::Global<SpringViewManipulationConfig>;
|
||||
|
||||
private Call getAStringCombiningCall() {
|
||||
exists(StringCombiningMethod m | result = m.getAReference())
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import semmle.code.java.dataflow.FlowSteps
|
||||
import semmle.code.java.frameworks.Servlets
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.TaintTracking2
|
||||
import DataFlow::PathGraph
|
||||
import MissingHttpOnlyFlow::PathGraph
|
||||
|
||||
/** Gets a regular expression for matching common names of sensitive cookies. */
|
||||
string getSensitiveCookieNameRegex() { result = "(?i).*(auth|session|token|key|credential).*" }
|
||||
@@ -65,18 +65,18 @@ class SetCookieMethodAccess extends MethodAccess {
|
||||
* A taint configuration tracking flow from the text `httponly` to argument 1 of
|
||||
* `SetCookieMethodAccess`.
|
||||
*/
|
||||
class MatchesHttpOnlyConfiguration extends TaintTracking2::Configuration {
|
||||
MatchesHttpOnlyConfiguration() { this = "MatchesHttpOnlyConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module MatchesHttpOnlyConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(CompileTimeConstantExpr).getStringValue().toLowerCase().matches("%httponly%")
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(SetCookieMethodAccess ma).getArgument(1)
|
||||
}
|
||||
}
|
||||
|
||||
module MatchesHttpOnlyFlow = TaintTracking::Global<MatchesHttpOnlyConfig>;
|
||||
|
||||
/** A class descended from `javax.servlet.http.Cookie`. */
|
||||
class CookieClass extends RefType {
|
||||
CookieClass() { this.getAnAncestor().hasQualifiedName("javax.servlet.http", "Cookie") }
|
||||
@@ -126,20 +126,20 @@ predicate isTestMethod(MethodAccess ma) {
|
||||
* A taint configuration tracking flow of a method that sets the `HttpOnly` flag,
|
||||
* or one that removes a cookie, to a `ServletResponse.addCookie` call.
|
||||
*/
|
||||
class SetHttpOnlyOrRemovesCookieConfiguration extends TaintTracking2::Configuration {
|
||||
SetHttpOnlyOrRemovesCookieConfiguration() { this = "SetHttpOnlyOrRemovesCookieConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module SetHttpOnlyOrRemovesCookieConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() =
|
||||
any(MethodAccess ma | setsCookieHttpOnly(ma) or removesCookie(ma)).getQualifier()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() =
|
||||
any(MethodAccess ma | ma.getMethod() instanceof ResponseAddCookieMethod).getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
module SetHttpOnlyOrRemovesCookieFlow = TaintTracking::Global<SetHttpOnlyOrRemovesCookieConfig>;
|
||||
|
||||
/**
|
||||
* A cookie that is added to an HTTP response and which doesn't have `httpOnly` set, used as a sink
|
||||
* in `MissingHttpOnlyConfiguration`.
|
||||
@@ -150,11 +150,11 @@ class CookieResponseSink extends DataFlow::ExprNode {
|
||||
(
|
||||
ma.getMethod() instanceof ResponseAddCookieMethod and
|
||||
this.getExpr() = ma.getArgument(0) and
|
||||
not exists(SetHttpOnlyOrRemovesCookieConfiguration cc | cc.hasFlowTo(this))
|
||||
not SetHttpOnlyOrRemovesCookieFlow::flowTo(this)
|
||||
or
|
||||
ma instanceof SetCookieMethodAccess and
|
||||
this.getExpr() = ma.getArgument(1) and
|
||||
not exists(MatchesHttpOnlyConfiguration cc | cc.hasFlowTo(this)) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure")
|
||||
not MatchesHttpOnlyFlow::flowTo(this) // response.addHeader("Set-Cookie", "token=" +authId + ";HttpOnly;Secure")
|
||||
) and
|
||||
not isTestMethod(ma) // Test class or method
|
||||
)
|
||||
@@ -181,21 +181,17 @@ predicate setsHttpOnlyInNewCookie(ClassInstanceExpr cie) {
|
||||
* A taint configuration tracking flow from a sensitive cookie without the `HttpOnly` flag
|
||||
* set to its HTTP response.
|
||||
*/
|
||||
class MissingHttpOnlyConfiguration extends TaintTracking::Configuration {
|
||||
MissingHttpOnlyConfiguration() { this = "MissingHttpOnlyConfiguration" }
|
||||
module MissingHttpOnlyConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveCookieNameExpr }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof SensitiveCookieNameExpr
|
||||
}
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof CookieResponseSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof CookieResponseSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
// JAX-RS's `new NewCookie("session-access-key", accessKey, "/", null, null, 0, true, true)` and similar
|
||||
setsHttpOnlyInNewCookie(node.asExpr())
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(
|
||||
ConstructorCall cc // new Cookie(...)
|
||||
|
|
||||
@@ -215,7 +211,9 @@ class MissingHttpOnlyConfiguration extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, MissingHttpOnlyConfiguration c
|
||||
where c.hasFlowPath(source, sink)
|
||||
module MissingHttpOnlyFlow = TaintTracking::Global<MissingHttpOnlyConfig>;
|
||||
|
||||
from MissingHttpOnlyFlow::PathNode source, MissingHttpOnlyFlow::PathNode sink
|
||||
where MissingHttpOnlyFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "$@ doesn't have the HttpOnly flag set.", source.getNode(),
|
||||
"This sensitive cookie"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking2
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.frameworks.android.Android
|
||||
|
||||
/** The `startActivityForResult` method of Android's `Activity` class. */
|
||||
@@ -29,27 +29,25 @@ class GetContentIntent extends ClassInstanceExpr {
|
||||
}
|
||||
|
||||
/** Taint configuration that identifies `GET_CONTENT` `Intent` instances passed to `startActivityForResult`. */
|
||||
class GetContentIntentConfig extends TaintTracking2::Configuration {
|
||||
GetContentIntentConfig() { this = "GetContentIntentConfig" }
|
||||
module GetContentIntentConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof GetContentIntent }
|
||||
|
||||
override predicate isSource(DataFlow2::Node src) { src.asExpr() instanceof GetContentIntent }
|
||||
|
||||
override predicate isSink(DataFlow2::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof StartActivityForResultMethod and sink.asExpr() = ma.getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet content) {
|
||||
super.allowImplicitRead(node, content)
|
||||
or
|
||||
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet content) {
|
||||
// Allow the wrapped intent created by Intent.getChooser to be consumed
|
||||
// by at the sink:
|
||||
this.isSink(node) and
|
||||
isSink(node) and
|
||||
allowIntentExtrasImplicitRead(node, content)
|
||||
}
|
||||
}
|
||||
|
||||
module GetContentsIntentFlow = TaintTracking::Global<GetContentIntentConfig>;
|
||||
|
||||
/** A `GET_CONTENT` `Intent` instances that is passed to `startActivityForResult`. */
|
||||
class AndroidFileIntentInput extends DataFlow::Node {
|
||||
MethodAccess ma;
|
||||
@@ -57,8 +55,8 @@ class AndroidFileIntentInput extends DataFlow::Node {
|
||||
AndroidFileIntentInput() {
|
||||
this.asExpr() = ma.getArgument(0) and
|
||||
ma.getMethod() instanceof StartActivityForResultMethod and
|
||||
exists(GetContentIntentConfig cc, GetContentIntent gi |
|
||||
cc.hasFlow(DataFlow::exprNode(gi), DataFlow::exprNode(ma.getArgument(0)))
|
||||
exists(GetContentIntent gi |
|
||||
GetContentsIntentFlow::flow(DataFlow::exprNode(gi), DataFlow::exprNode(ma.getArgument(0)))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,19 +16,20 @@ import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.PathSanitizer
|
||||
import AndroidWebResourceResponse
|
||||
import DataFlow::PathGraph
|
||||
import InsecureWebResourceResponseFlow::PathGraph
|
||||
|
||||
class InsecureWebResourceResponseConfig extends TaintTracking::Configuration {
|
||||
InsecureWebResourceResponseConfig() { this = "InsecureWebResourceResponseConfig" }
|
||||
module InsecureWebResourceResponseConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof WebResourceResponseSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof WebResourceResponseSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof PathInjectionSanitizer }
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof PathInjectionSanitizer }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, InsecureWebResourceResponseConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module InsecureWebResourceResponseFlow = TaintTracking::Global<InsecureWebResourceResponseConfig>;
|
||||
|
||||
from
|
||||
InsecureWebResourceResponseFlow::PathNode source, InsecureWebResourceResponseFlow::PathNode sink
|
||||
where InsecureWebResourceResponseFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Leaking arbitrary content in Android from $@.",
|
||||
source.getNode(), "this user input"
|
||||
|
||||
@@ -14,7 +14,7 @@ import java
|
||||
import semmle.code.java.controlflow.Guards
|
||||
import AndroidFileIntentSink
|
||||
import AndroidFileIntentSource
|
||||
import DataFlow::PathGraph
|
||||
import AndroidFileLeakFlow::PathGraph
|
||||
|
||||
private predicate startsWithSanitizer(Guard g, Expr e, boolean branch) {
|
||||
exists(MethodAccess ma |
|
||||
@@ -25,16 +25,14 @@ private predicate startsWithSanitizer(Guard g, Expr e, boolean branch) {
|
||||
)
|
||||
}
|
||||
|
||||
class AndroidFileLeakConfig extends TaintTracking::Configuration {
|
||||
AndroidFileLeakConfig() { this = "AndroidFileLeakConfig" }
|
||||
|
||||
module AndroidFileLeakConfig implements DataFlow::ConfigSig {
|
||||
/**
|
||||
* Holds if `src` is a read of some Intent-typed variable guarded by a check like
|
||||
* `requestCode == someCode`, where `requestCode` is the first
|
||||
* argument to `Activity.onActivityResult` and `someCode` is
|
||||
* any request code used in a call to `startActivityForResult(intent, someCode)`.
|
||||
*/
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
predicate isSource(DataFlow::Node src) {
|
||||
exists(
|
||||
OnActivityForResultMethod oafr, ConditionBlock cb, CompileTimeConstantExpr cc,
|
||||
VarAccess intentVar
|
||||
@@ -50,9 +48,9 @@ class AndroidFileLeakConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
|
||||
/** Holds if it is a sink of file access in Android. */
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof AndroidFileSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof AndroidFileSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node prev, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node prev, DataFlow::Node succ) {
|
||||
exists(MethodAccess aema, AsyncTaskRunInBackgroundMethod arm |
|
||||
// fileAsyncTask.execute(params) will invoke doInBackground(params) of FileAsyncTask
|
||||
aema.getQualifier().getType() = arm.getDeclaringType() and
|
||||
@@ -72,12 +70,14 @@ class AndroidFileLeakConfig extends TaintTracking::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node = DataFlow::BarrierGuard<startsWithSanitizer/3>::getABarrierNode()
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, AndroidFileLeakConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module AndroidFileLeakFlow = TaintTracking::Global<AndroidFileLeakConfig>;
|
||||
|
||||
from AndroidFileLeakFlow::PathNode source, AndroidFileLeakFlow::PathNode sink
|
||||
where AndroidFileLeakFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Leaking arbitrary Android file from $@.", source.getNode(),
|
||||
"this user input"
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
import semmle.code.java.controlflow.Guards
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.TaintTracking2
|
||||
import semmle.code.java.dataflow.DataFlow3
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
/** A method call that produces cryptographic result. */
|
||||
@@ -51,10 +49,8 @@ private class ProduceSignatureCall extends ProduceCryptoCall {
|
||||
* A config that tracks data flow from initializing a cipher for encryption
|
||||
* to producing a ciphertext using this cipher.
|
||||
*/
|
||||
private class InitializeEncryptorConfig extends DataFlow3::Configuration {
|
||||
InitializeEncryptorConfig() { this = "InitializeEncryptorConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
private module InitializeEncryptorConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod().hasQualifiedName("javax.crypto", "Cipher", "init") and
|
||||
ma.getArgument(0).(VarAccess).getVariable().hasName("ENCRYPT_MODE") and
|
||||
@@ -62,7 +58,7 @@ private class InitializeEncryptorConfig extends DataFlow3::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod().hasQualifiedName("javax.crypto", "Cipher", "doFinal") and
|
||||
ma.getQualifier() = sink.asExpr()
|
||||
@@ -70,6 +66,8 @@ private class InitializeEncryptorConfig extends DataFlow3::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
private module InitializeEncryptorFlow = DataFlow::Global<InitializeEncryptorConfig>;
|
||||
|
||||
/** A method call that produces a ciphertext. */
|
||||
private class ProduceCiphertextCall extends ProduceCryptoCall {
|
||||
ProduceCiphertextCall() {
|
||||
@@ -90,9 +88,7 @@ private class ProduceCiphertextCall extends ProduceCryptoCall {
|
||||
this.getArgument(1) = output
|
||||
)
|
||||
) and
|
||||
exists(InitializeEncryptorConfig config |
|
||||
config.hasFlowTo(DataFlow3::exprNode(this.getQualifier()))
|
||||
)
|
||||
InitializeEncryptorFlow::flowToExpr(this.getQualifier())
|
||||
}
|
||||
|
||||
override string getResultType() { result = "ciphertext" }
|
||||
@@ -151,16 +147,14 @@ private predicate updateMessageDigestStep(DataFlow2::Node fromNode, DataFlow2::N
|
||||
* A config that tracks data flow from remote user input to a cryptographic operation
|
||||
* such as cipher, MAC or signature.
|
||||
*/
|
||||
private class UserInputInCryptoOperationConfig extends TaintTracking2::Configuration {
|
||||
UserInputInCryptoOperationConfig() { this = "UserInputInCryptoOperationConfig" }
|
||||
private module UserInputInCryptoOperationConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(ProduceCryptoCall call | call.getQualifier() = sink.asExpr())
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow2::Node fromNode, DataFlow2::Node toNode) {
|
||||
predicate isAdditionalFlowStep(DataFlow2::Node fromNode, DataFlow2::Node toNode) {
|
||||
updateCryptoOperationStep(fromNode, toNode)
|
||||
or
|
||||
createMessageDigestStep(fromNode, toNode)
|
||||
@@ -169,6 +163,13 @@ private class UserInputInCryptoOperationConfig extends TaintTracking2::Configura
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow from remote user input to a cryptographic operation
|
||||
* such as cipher, MAC or signature.
|
||||
*/
|
||||
private module UserInputInCryptoOperationFlow =
|
||||
TaintTracking::Global<UserInputInCryptoOperationConfig>;
|
||||
|
||||
/** A source that produces result of cryptographic operation. */
|
||||
class CryptoOperationSource extends DataFlow::Node {
|
||||
ProduceCryptoCall call;
|
||||
@@ -177,8 +178,8 @@ class CryptoOperationSource extends DataFlow::Node {
|
||||
|
||||
/** Holds if remote user input was used in the cryptographic operation. */
|
||||
predicate includesUserInput() {
|
||||
exists(DataFlow2::PathNode sink, UserInputInCryptoOperationConfig config |
|
||||
config.hasFlowPath(_, sink)
|
||||
exists(UserInputInCryptoOperationFlow::PathNode sink |
|
||||
UserInputInCryptoOperationFlow::flowPath(_, sink)
|
||||
|
|
||||
sink.getNode().asExpr() = call.getQualifier()
|
||||
)
|
||||
@@ -212,12 +213,10 @@ private class NonConstantTimeComparisonCall extends StaticMethodAccess {
|
||||
* A config that tracks data flow from remote user input to methods
|
||||
* that compare inputs using a non-constant-time algorithm.
|
||||
*/
|
||||
private class UserInputInComparisonConfig extends TaintTracking2::Configuration {
|
||||
UserInputInComparisonConfig() { this = "UserInputInComparisonConfig" }
|
||||
private module UserInputInComparisonConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(NonConstantTimeEqualsCall call |
|
||||
sink.asExpr() = [call.getAnArgument(), call.getQualifier()]
|
||||
)
|
||||
@@ -226,6 +225,8 @@ private class UserInputInComparisonConfig extends TaintTracking2::Configuration
|
||||
}
|
||||
}
|
||||
|
||||
private module UserInputInComparisonFlow = TaintTracking::Global<UserInputInComparisonConfig>;
|
||||
|
||||
/** Holds if `expr` looks like a constant. */
|
||||
private predicate looksLikeConstant(Expr expr) {
|
||||
expr.isCompileTimeConstant()
|
||||
@@ -301,21 +302,18 @@ class NonConstantTimeComparisonSink extends DataFlow::Node {
|
||||
}
|
||||
|
||||
/** Holds if remote user input was used in the comparison. */
|
||||
predicate includesUserInput() {
|
||||
exists(UserInputInComparisonConfig config |
|
||||
config.hasFlowTo(DataFlow2::exprNode(anotherParameter))
|
||||
)
|
||||
}
|
||||
predicate includesUserInput() { UserInputInComparisonFlow::flowToExpr(anotherParameter) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration that tracks data flow from cryptographic operations
|
||||
* to methods that compare data using a non-constant-time algorithm.
|
||||
*/
|
||||
class NonConstantTimeCryptoComparisonConfig extends TaintTracking::Configuration {
|
||||
NonConstantTimeCryptoComparisonConfig() { this = "NonConstantTimeCryptoComparisonConfig" }
|
||||
module NonConstantTimeCryptoComparisonConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof CryptoOperationSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof CryptoOperationSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof NonConstantTimeComparisonSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof NonConstantTimeComparisonSink }
|
||||
}
|
||||
|
||||
module NonConstantTimeCryptoComparisonFlow =
|
||||
TaintTracking::Global<NonConstantTimeCryptoComparisonConfig>;
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
|
||||
import java
|
||||
import NonConstantTimeCheckOnSignatureQuery
|
||||
import DataFlow::PathGraph
|
||||
import NonConstantTimeCryptoComparisonFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, NonConstantTimeCryptoComparisonConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from
|
||||
NonConstantTimeCryptoComparisonFlow::PathNode source,
|
||||
NonConstantTimeCryptoComparisonFlow::PathNode sink
|
||||
where NonConstantTimeCryptoComparisonFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Possible timing attack against $@ validation.", source,
|
||||
source.getNode().(CryptoOperationSource).getCall().getResultType()
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import DataFlow::PathGraph
|
||||
import NonConstantTimeComparisonFlow::PathGraph
|
||||
|
||||
/** A static method that uses a non-constant-time algorithm for comparing inputs. */
|
||||
private class NonConstantTimeComparisonCall extends StaticMethodAccess {
|
||||
@@ -54,20 +54,18 @@ class ClientSuppliedIpTokenCheck extends DataFlow::Node {
|
||||
}
|
||||
}
|
||||
|
||||
class NonConstantTimeComparisonConfig extends TaintTracking::Configuration {
|
||||
NonConstantTimeComparisonConfig() { this = "NonConstantTimeComparisonConfig" }
|
||||
module NonConstantTimeComparisonConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ClientSuppliedIpTokenCheck }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source instanceof ClientSuppliedIpTokenCheck
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
isNonConstantEqualsCallArgument(sink.asExpr()) or
|
||||
isNonConstantComparisonCallArgument(sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, NonConstantTimeComparisonConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module NonConstantTimeComparisonFlow = TaintTracking::Global<NonConstantTimeComparisonConfig>;
|
||||
|
||||
from NonConstantTimeComparisonFlow::PathNode source, NonConstantTimeComparisonFlow::PathNode sink
|
||||
where NonConstantTimeComparisonFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Possible timing attack against $@ validation.",
|
||||
source.getNode(), "client-supplied token"
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
import java
|
||||
import NonConstantTimeCheckOnSignatureQuery
|
||||
import DataFlow::PathGraph
|
||||
import NonConstantTimeCryptoComparisonFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, NonConstantTimeCryptoComparisonConfig conf
|
||||
from
|
||||
NonConstantTimeCryptoComparisonFlow::PathNode source,
|
||||
NonConstantTimeCryptoComparisonFlow::PathNode sink
|
||||
where
|
||||
conf.hasFlowPath(source, sink) and
|
||||
NonConstantTimeCryptoComparisonFlow::flowPath(source, sink) and
|
||||
(
|
||||
source.getNode().(CryptoOperationSource).includesUserInput() and
|
||||
sink.getNode().(NonConstantTimeComparisonSink).includesUserInput()
|
||||
|
||||
@@ -66,16 +66,14 @@ private class JxBrowserSafeLoadHandler extends RefType {
|
||||
* Models flow from the source `new Browser()` to a sink `browser.setLoadHandler(loadHandler)` where `loadHandler`
|
||||
* has been determined to be safe.
|
||||
*/
|
||||
private class JxBrowserFlowConfiguration extends DataFlow::Configuration {
|
||||
JxBrowserFlowConfiguration() { this = "JxBrowserFlowConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
private module JxBrowserFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) {
|
||||
exists(ClassInstanceExpr newJxBrowser | newJxBrowser.getConstructedType() instanceof JxBrowser |
|
||||
newJxBrowser = src.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma | ma.getMethod() instanceof JxBrowserSetLoadHandler |
|
||||
ma.getArgument(0).getType() instanceof JxBrowserSafeLoadHandler and
|
||||
ma.getQualifier() = sink.asExpr()
|
||||
@@ -83,9 +81,11 @@ private class JxBrowserFlowConfiguration extends DataFlow::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from JxBrowserFlowConfiguration cfg, DataFlow::Node src
|
||||
private module JxBrowserFlow = DataFlow::Global<JxBrowserFlowConfig>;
|
||||
|
||||
from DataFlow::Node src
|
||||
where
|
||||
cfg.isSource(src) and
|
||||
not cfg.hasFlow(src, _) and
|
||||
JxBrowserFlowConfig::isSource(src) and
|
||||
not JxBrowserFlow::flow(src, _) and
|
||||
not isSafeJxBrowserVersion()
|
||||
select src, "This JxBrowser instance may not check HTTPS certificates."
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
|
||||
import java
|
||||
import RevocationCheckingLib
|
||||
import DataFlow::PathGraph
|
||||
import DisabledRevocationCheckingFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, DisabledRevocationCheckingConfig config
|
||||
where config.hasFlowPath(source, sink)
|
||||
from DisabledRevocationCheckingFlow::PathNode source, DisabledRevocationCheckingFlow::PathNode sink
|
||||
where DisabledRevocationCheckingFlow::flowPath(source, sink)
|
||||
select source.getNode(), source, sink, "This disables revocation checking."
|
||||
|
||||
@@ -5,16 +5,16 @@ import DataFlow
|
||||
/**
|
||||
* A taint-tracking configuration for disabling revocation checking.
|
||||
*/
|
||||
class DisabledRevocationCheckingConfig extends TaintTracking::Configuration {
|
||||
DisabledRevocationCheckingConfig() { this = "DisabledRevocationCheckingConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(BooleanLiteral b | b.getBooleanValue() = false | source.asExpr() = b)
|
||||
module DisabledRevocationCheckingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(BooleanLiteral).getBooleanValue() = false
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof SetRevocationEnabledSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof SetRevocationEnabledSink }
|
||||
}
|
||||
|
||||
module DisabledRevocationCheckingFlow = TaintTracking::Global<DisabledRevocationCheckingConfig>;
|
||||
|
||||
/**
|
||||
* A sink that disables revocation checking,
|
||||
* i.e. calling `PKIXParameters.setRevocationEnabled(false)`
|
||||
|
||||
@@ -50,12 +50,8 @@ predicate isCreatingAzureClientSideEncryptionObjectNewVersion(Call call, Class c
|
||||
/**
|
||||
* A dataflow config that tracks `EncryptedBlobClientBuilder.version` argument initialization.
|
||||
*/
|
||||
private class EncryptedBlobClientBuilderSafeEncryptionVersionConfig extends DataFlow::Configuration {
|
||||
EncryptedBlobClientBuilderSafeEncryptionVersionConfig() {
|
||||
this = "EncryptedBlobClientBuilderSafeEncryptionVersionConfig"
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
private module EncryptedBlobClientBuilderSafeEncryptionVersionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(FieldRead fr, Field f | fr = source.asExpr() |
|
||||
f.getAnAccess() = fr and
|
||||
f.hasQualifiedName("com.azure.storage.blob.specialized.cryptography", "EncryptionVersion",
|
||||
@@ -63,21 +59,22 @@ private class EncryptedBlobClientBuilderSafeEncryptionVersionConfig extends Data
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
isCreatingAzureClientSideEncryptionObjectNewVersion(_, _, sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
private module EncryptedBlobClientBuilderSafeEncryptionVersionFlow =
|
||||
DataFlow::Global<EncryptedBlobClientBuilderSafeEncryptionVersionConfig>;
|
||||
|
||||
/**
|
||||
* Holds if `call` is an object creation for a class `EncryptedBlobClientBuilder`
|
||||
* that takes `versionArg` as the argument specifying the encryption version, and that version is safe.
|
||||
*/
|
||||
predicate isCreatingSafeAzureClientSideEncryptionObject(Call call, Class c, Expr versionArg) {
|
||||
isCreatingAzureClientSideEncryptionObjectNewVersion(call, c, versionArg) and
|
||||
exists(EncryptedBlobClientBuilderSafeEncryptionVersionConfig config, DataFlow::Node sink |
|
||||
sink.asExpr() = versionArg
|
||||
|
|
||||
config.hasFlow(_, sink)
|
||||
exists(DataFlow::Node sink | sink.asExpr() = versionArg |
|
||||
EncryptedBlobClientBuilderSafeEncryptionVersionFlow::flowTo(sink)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
import java
|
||||
import semmle.code.java.security.Encryption
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import DataFlow
|
||||
import PathGraph
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unsafe SSL and TLS versions.
|
||||
*/
|
||||
class UnsafeTlsVersionConfig extends TaintTracking::Configuration {
|
||||
UnsafeTlsVersionConfig() { this = "UnsafeTlsVersion::UnsafeTlsVersionConfig" }
|
||||
module UnsafeTlsVersionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof UnsafeTlsVersion }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof UnsafeTlsVersion }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof SslContextGetInstanceSink or
|
||||
sink instanceof CreateSslParametersSink or
|
||||
sink instanceof SslParametersSetProtocolsSink or
|
||||
@@ -20,6 +16,8 @@ class UnsafeTlsVersionConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
module UnsafeTlsVersionFlow = TaintTracking::Global<UnsafeTlsVersionConfig>;
|
||||
|
||||
/**
|
||||
* A sink that sets protocol versions in `SSLContext`,
|
||||
* i.e `SSLContext.getInstance(protocol)`.
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import java
|
||||
import SslLib
|
||||
import DataFlow::PathGraph
|
||||
import UnsafeTlsVersionFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeTlsVersionConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from UnsafeTlsVersionFlow::PathNode source, UnsafeTlsVersionFlow::PathNode sink
|
||||
where UnsafeTlsVersionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "$@ is unsafe.", source.getNode(),
|
||||
source.getNode().asExpr().(StringLiteral).getValue()
|
||||
|
||||
@@ -14,8 +14,7 @@ import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.frameworks.Servlets
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.TaintTracking2
|
||||
import DataFlow::PathGraph
|
||||
import CorsOriginFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if `header` sets `Access-Control-Allow-Credentials` to `true`. This ensures fair chances of exploitability.
|
||||
@@ -48,24 +47,25 @@ private Expr getAccessControlAllowOriginHeaderName() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This taintflow2 configuration checks if there is a flow from source node towards CorsProbableCheckAccess methods.
|
||||
* A taint-tracking configuration for flow from a source node to CorsProbableCheckAccess methods.
|
||||
*/
|
||||
class CorsSourceReachesCheckConfig extends TaintTracking2::Configuration {
|
||||
CorsSourceReachesCheckConfig() { this = "CorsOriginConfig" }
|
||||
module CorsSourceReachesCheckConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { CorsOriginFlow::flow(source, _) }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { any(CorsOriginConfig c).hasFlow(source, _) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(CorsProbableCheckAccess check).getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
private class CorsOriginConfig extends TaintTracking::Configuration {
|
||||
CorsOriginConfig() { this = "CorsOriginConfig" }
|
||||
/**
|
||||
* Taint-tracking flow from a source node to CorsProbableCheckAccess methods.
|
||||
*/
|
||||
module CorsSourceReachesCheckFlow = TaintTracking::Global<CorsSourceReachesCheckConfig>;
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
private module CorsOriginConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess corsHeader, MethodAccess allowCredentialsHeader |
|
||||
(
|
||||
corsHeader.getMethod() instanceof ResponseSetHeaderMethod or
|
||||
@@ -79,9 +79,11 @@ private class CorsOriginConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, CorsOriginConfig conf,
|
||||
CorsSourceReachesCheckConfig sanconf
|
||||
where conf.hasFlowPath(source, sink) and not sanconf.hasFlow(source.getNode(), _)
|
||||
private module CorsOriginFlow = TaintTracking::Global<CorsOriginConfig>;
|
||||
|
||||
from CorsOriginFlow::PathNode source, CorsOriginFlow::PathNode sink
|
||||
where
|
||||
CorsOriginFlow::flowPath(source, sink) and
|
||||
not CorsSourceReachesCheckFlow::flow(source.getNode(), _)
|
||||
select sink.getNode(), source, sink, "CORS header is being set using user controlled value $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -12,29 +12,26 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import ClientSuppliedIpUsedInSecurityCheckLib
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
import ClientSuppliedIpUsedInSecurityCheckLib
|
||||
import ClientSuppliedIpUsedInSecurityCheckFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Taint-tracking configuration tracing flow from obtaining a client ip from an HTTP header to a sensitive use.
|
||||
*/
|
||||
class ClientSuppliedIpUsedInSecurityCheckConfig extends TaintTracking::Configuration {
|
||||
ClientSuppliedIpUsedInSecurityCheckConfig() { this = "ClientSuppliedIpUsedInSecurityCheckConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module ClientSuppliedIpUsedInSecurityCheckConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof ClientSuppliedIpUsedInSecurityCheck
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof ClientSuppliedIpUsedInSecurityCheckSink
|
||||
}
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof ClientSuppliedIpUsedInSecurityCheckSink }
|
||||
|
||||
/**
|
||||
* Splitting a header value by `,` and taking an entry other than the first is sanitizing, because
|
||||
* later entries may originate from more-trustworthy intermediate proxies, not the original client.
|
||||
*/
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(ArrayAccess aa, MethodAccess ma | aa.getArray() = ma |
|
||||
ma.getQualifier() = node.asExpr() and
|
||||
ma.getMethod() instanceof SplitMethod and
|
||||
@@ -47,8 +44,12 @@ class ClientSuppliedIpUsedInSecurityCheckConfig extends TaintTracking::Configura
|
||||
}
|
||||
}
|
||||
|
||||
module ClientSuppliedIpUsedInSecurityCheckFlow =
|
||||
TaintTracking::Global<ClientSuppliedIpUsedInSecurityCheckConfig>;
|
||||
|
||||
from
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, ClientSuppliedIpUsedInSecurityCheckConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
ClientSuppliedIpUsedInSecurityCheckFlow::PathNode source,
|
||||
ClientSuppliedIpUsedInSecurityCheckFlow::PathNode sink
|
||||
where ClientSuppliedIpUsedInSecurityCheckFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "IP address spoofing might include code from $@.",
|
||||
source.getNode(), "this user input"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/** Json string type data. */
|
||||
abstract class JsonStringSource extends DataFlow::Node { }
|
||||
|
||||
@@ -12,35 +12,37 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import JsonpInjectionLib
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.deadcode.WebEntryPoints
|
||||
import DataFlow::PathGraph
|
||||
import semmle.code.java.security.XSS
|
||||
import JsonpInjectionLib
|
||||
import RequestResponseFlow::PathGraph
|
||||
|
||||
/** Taint-tracking configuration tracing flow from get method request sources to output jsonp data. */
|
||||
class RequestResponseFlowConfig extends TaintTracking::Configuration {
|
||||
RequestResponseFlowConfig() { this = "RequestResponseFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module RequestResponseFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof RemoteFlowSource and
|
||||
any(RequestGetMethod m).polyCalls*(source.getEnclosingCallable())
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof XssSink and
|
||||
any(RequestGetMethod m).polyCalls*(sink.getEnclosingCallable())
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(MethodAccess ma |
|
||||
isRequestGetParamMethod(ma) and pred.asExpr() = ma.getQualifier() and succ.asExpr() = ma
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, RequestResponseFlowConfig conf
|
||||
module RequestResponseFlow = TaintTracking::Global<RequestResponseFlowConfig>;
|
||||
|
||||
from RequestResponseFlow::PathNode source, RequestResponseFlow::PathNode sink
|
||||
where
|
||||
conf.hasFlowPath(source, sink) and
|
||||
exists(JsonpInjectionFlowConfig jhfc | jhfc.hasFlowTo(sink.getNode()))
|
||||
RequestResponseFlow::flowPath(source, sink) and
|
||||
JsonpInjectionFlow::flowTo(sink.getNode())
|
||||
select sink.getNode(), source, sink, "Jsonp response might include code from $@.", source.getNode(),
|
||||
"this user input"
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import java
|
||||
import DataFlow
|
||||
import JsonStringLib
|
||||
import semmle.code.java.security.XSS
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.DataFlow3
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.frameworks.spring.SpringController
|
||||
private import JsonStringLib
|
||||
private import semmle.code.java.security.XSS
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
/**
|
||||
* A method that is called to handle an HTTP GET request.
|
||||
@@ -81,38 +78,38 @@ class JsonpBuilderExpr extends AddExpr {
|
||||
}
|
||||
|
||||
/** A data flow configuration tracing flow from remote sources to jsonp function name. */
|
||||
class RemoteFlowConfig extends DataFlow2::Configuration {
|
||||
RemoteFlowConfig() { this = "RemoteFlowConfig" }
|
||||
module RemoteFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(JsonpBuilderExpr jhe | jhe.getFunctionName() = sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
module RemoteFlow = DataFlow::Global<RemoteFlowConfig>;
|
||||
|
||||
/** A data flow configuration tracing flow from json data into the argument `json` of JSONP-like string `someFunctionName + "(" + json + ")"`. */
|
||||
class JsonDataFlowConfig extends DataFlow2::Configuration {
|
||||
JsonDataFlowConfig() { this = "JsonDataFlowConfig" }
|
||||
module JsonDataFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof JsonStringSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof JsonStringSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(JsonpBuilderExpr jhe | jhe.getJsonExpr() = sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/** Taint-tracking configuration tracing flow from probable jsonp data with a user-controlled function name to an outgoing HTTP entity. */
|
||||
class JsonpInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
JsonpInjectionFlowConfig() { this = "JsonpInjectionFlowConfig" }
|
||||
module JsonDataFlow = DataFlow::Global<JsonDataFlowConfig>;
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
exists(JsonpBuilderExpr jhe, JsonDataFlowConfig jdfc, RemoteFlowConfig rfc |
|
||||
/** Taint-tracking configuration tracing flow from probable jsonp data with a user-controlled function name to an outgoing HTTP entity. */
|
||||
module JsonpInjectionFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) {
|
||||
exists(JsonpBuilderExpr jhe |
|
||||
jhe = src.asExpr() and
|
||||
jdfc.hasFlowTo(DataFlow::exprNode(jhe.getJsonExpr())) and
|
||||
rfc.hasFlowTo(DataFlow::exprNode(jhe.getFunctionName()))
|
||||
JsonDataFlow::flowTo(DataFlow::exprNode(jhe.getJsonExpr())) and
|
||||
RemoteFlow::flowTo(DataFlow::exprNode(jhe.getFunctionName()))
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
|
||||
}
|
||||
|
||||
module JsonpInjectionFlow = TaintTracking::Global<JsonpInjectionFlowConfig>;
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
|
||||
import java
|
||||
import ThreadResourceAbuse
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
import ThreadResourceAbuseFlow::PathGraph
|
||||
|
||||
/** The `getInitParameter` method of servlet or JSF. */
|
||||
class GetInitParameter extends Method {
|
||||
@@ -41,18 +42,16 @@ class InitParameterInput extends LocalUserInput {
|
||||
}
|
||||
|
||||
/** Taint configuration of uncontrolled thread resource consumption from local user input. */
|
||||
class ThreadResourceAbuse extends TaintTracking::Configuration {
|
||||
ThreadResourceAbuse() { this = "ThreadResourceAbuse" }
|
||||
module ThreadResourceAbuseConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof PauseThreadSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof PauseThreadSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
any(AdditionalValueStep r).step(pred, succ)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(
|
||||
MethodAccess ma // Math.min(sleepTime, MAX_INTERVAL)
|
||||
|
|
||||
@@ -64,7 +63,9 @@ class ThreadResourceAbuse extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, ThreadResourceAbuse conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module ThreadResourceAbuseFlow = TaintTracking::Global<ThreadResourceAbuseConfig>;
|
||||
|
||||
from ThreadResourceAbuseFlow::PathNode source, ThreadResourceAbuseFlow::PathNode sink
|
||||
where ThreadResourceAbuseFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Possible uncontrolled resource consumption due to $@.",
|
||||
source.getNode(), "local user-provided value"
|
||||
|
||||
@@ -13,21 +13,19 @@
|
||||
import java
|
||||
import ThreadResourceAbuse
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
import ThreadResourceAbuseFlow::PathGraph
|
||||
|
||||
/** Taint configuration of uncontrolled thread resource consumption. */
|
||||
class ThreadResourceAbuse extends TaintTracking::Configuration {
|
||||
ThreadResourceAbuse() { this = "ThreadResourceAbuse" }
|
||||
module ThreadResourceAbuseConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof PauseThreadSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof PauseThreadSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
any(AdditionalValueStep r).step(pred, succ)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(
|
||||
MethodAccess ma // Math.min(sleepTime, MAX_INTERVAL)
|
||||
|
|
||||
@@ -39,8 +37,10 @@ class ThreadResourceAbuse extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, ThreadResourceAbuse conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module ThreadResourceAbuseFlow = TaintTracking::Global<ThreadResourceAbuseConfig>;
|
||||
|
||||
from ThreadResourceAbuseFlow::PathNode source, ThreadResourceAbuseFlow::PathNode sink
|
||||
where ThreadResourceAbuseFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"Vulnerability of uncontrolled resource consumption due to $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -17,7 +17,7 @@ import UnsafeReflectionLib
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.controlflow.Guards
|
||||
import DataFlow::PathGraph
|
||||
import UnsafeReflectionFlow::PathGraph
|
||||
|
||||
private predicate containsSanitizer(Guard g, Expr e, boolean branch) {
|
||||
g.(MethodAccess).getMethod().hasName("contains") and
|
||||
@@ -31,14 +31,12 @@ private predicate equalsSanitizer(Guard g, Expr e, boolean branch) {
|
||||
branch = true
|
||||
}
|
||||
|
||||
class UnsafeReflectionConfig extends TaintTracking::Configuration {
|
||||
UnsafeReflectionConfig() { this = "UnsafeReflectionConfig" }
|
||||
module UnsafeReflectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeReflectionSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeReflectionSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
// Argument -> return of Class.forName, ClassLoader.loadClass
|
||||
exists(ReflectiveClassIdentifierMethodAccess rcimac |
|
||||
rcimac.getArgument(0) = pred.asExpr() and rcimac = succ.asExpr()
|
||||
@@ -75,12 +73,14 @@ class UnsafeReflectionConfig extends TaintTracking::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node = DataFlow::BarrierGuard<containsSanitizer/3>::getABarrierNode() or
|
||||
node = DataFlow::BarrierGuard<equalsSanitizer/3>::getABarrierNode()
|
||||
}
|
||||
}
|
||||
|
||||
module UnsafeReflectionFlow = TaintTracking::Global<UnsafeReflectionConfig>;
|
||||
|
||||
private Expr getAMethodArgument(MethodAccess reflectiveCall) {
|
||||
result = reflectiveCall.(NewInstance).getAnArgument()
|
||||
or
|
||||
@@ -88,10 +88,10 @@ private Expr getAMethodArgument(MethodAccess reflectiveCall) {
|
||||
}
|
||||
|
||||
from
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeReflectionConfig conf,
|
||||
UnsafeReflectionFlow::PathNode source, UnsafeReflectionFlow::PathNode sink,
|
||||
MethodAccess reflectiveCall
|
||||
where
|
||||
conf.hasFlowPath(source, sink) and
|
||||
UnsafeReflectionFlow::flowPath(source, sink) and
|
||||
sink.getNode().asExpr() = reflectiveCall.getQualifier() and
|
||||
conf.hasFlowToExpr(getAMethodArgument(reflectiveCall))
|
||||
UnsafeReflectionFlow::flowToExpr(getAMethodArgument(reflectiveCall))
|
||||
select sink.getNode(), source, sink, "Unsafe reflection of $@.", source.getNode(), "user input"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.frameworks.Rmi
|
||||
import DataFlow::PathGraph
|
||||
import BindingUnsafeRemoteObjectFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A method that binds a name to a remote object.
|
||||
@@ -48,22 +48,20 @@ private predicate hasVulnerableMethod(RefType type) {
|
||||
* A taint-tracking configuration for unsafe remote objects
|
||||
* that are vulnerable to deserialization attacks.
|
||||
*/
|
||||
private class BindingUnsafeRemoteObjectConfig extends TaintTracking::Configuration {
|
||||
BindingUnsafeRemoteObjectConfig() { this = "BindingUnsafeRemoteObjectConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
private module BindingUnsafeRemoteObjectConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(ConstructorCall cc | cc = source.asExpr() |
|
||||
hasVulnerableMethod(cc.getConstructedType().getAnAncestor())
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma | ma.getArgument(1) = sink.asExpr() |
|
||||
ma.getMethod() instanceof BindMethod
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||
m.getDeclaringType().hasQualifiedName("java.rmi.server", "UnicastRemoteObject") and
|
||||
m.hasName("exportObject") and
|
||||
@@ -74,6 +72,9 @@ private class BindingUnsafeRemoteObjectConfig extends TaintTracking::Configurati
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, BindingUnsafeRemoteObjectConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
private module BindingUnsafeRemoteObjectFlow =
|
||||
TaintTracking::Global<BindingUnsafeRemoteObjectConfig>;
|
||||
|
||||
from BindingUnsafeRemoteObjectFlow::PathNode source, BindingUnsafeRemoteObjectFlow::PathNode sink
|
||||
where BindingUnsafeRemoteObjectFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Unsafe deserialization in a remote object."
|
||||
|
||||
@@ -17,12 +17,10 @@ import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import experimental.semmle.code.java.frameworks.Jsf
|
||||
import semmle.code.java.security.PathSanitizer
|
||||
import DataFlow::PathGraph
|
||||
import UnsafeUrlForwardFlow::PathGraph
|
||||
|
||||
class UnsafeUrlForwardFlowConfig extends TaintTracking::Configuration {
|
||||
UnsafeUrlForwardFlowConfig() { this = "UnsafeUrlForwardFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module UnsafeUrlForwardFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof RemoteFlowSource and
|
||||
not exists(MethodAccess ma, Method m | ma.getMethod() = m |
|
||||
(
|
||||
@@ -34,18 +32,16 @@ class UnsafeUrlForwardFlowConfig extends TaintTracking::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeUrlForwardSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeUrlForwardSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node instanceof UnsafeUrlForwardSanitizer or
|
||||
node instanceof PathInjectionSanitizer
|
||||
}
|
||||
|
||||
override DataFlow::FlowFeature getAFeature() {
|
||||
result instanceof DataFlow::FeatureHasSourceCallContext
|
||||
}
|
||||
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node prev, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node prev, DataFlow::Node succ) {
|
||||
exists(MethodAccess ma |
|
||||
(
|
||||
ma.getMethod() instanceof GetServletResourceMethod or
|
||||
@@ -60,7 +56,9 @@ class UnsafeUrlForwardFlowConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeUrlForwardFlowConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module UnsafeUrlForwardFlow = TaintTracking::Global<UnsafeUrlForwardFlowConfig>;
|
||||
|
||||
from UnsafeUrlForwardFlow::PathNode source, UnsafeUrlForwardFlow::PathNode sink
|
||||
where UnsafeUrlForwardFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Potentially untrusted URL forward due to $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -14,7 +14,7 @@ import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.SensitiveActions
|
||||
import DataFlow::PathGraph
|
||||
import SensitiveGetQueryFlow::PathGraph
|
||||
|
||||
/** A variable that holds sensitive information judging by its name. */
|
||||
class SensitiveInfoExpr extends Expr {
|
||||
@@ -59,22 +59,22 @@ class RequestGetParamSource extends DataFlow::ExprNode {
|
||||
}
|
||||
|
||||
/** A taint configuration tracking flow from the `ServletRequest` of a GET request handler to an expression whose name suggests it holds security-sensitive data. */
|
||||
class SensitiveGetQueryConfiguration extends TaintTracking::Configuration {
|
||||
SensitiveGetQueryConfiguration() { this = "SensitiveGetQueryConfiguration" }
|
||||
module SensitiveGetQueryConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RequestGetParamSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RequestGetParamSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof SensitiveInfoExpr }
|
||||
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof SensitiveInfoExpr }
|
||||
|
||||
/** Holds if the node is in a servlet method other than `doGet`. */
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
isServletRequestMethod(node.getEnclosingCallable()) and
|
||||
not isGetServletMethod(node.getEnclosingCallable())
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, SensitiveGetQueryConfiguration c
|
||||
where c.hasFlowPath(source, sink)
|
||||
module SensitiveGetQueryFlow = TaintTracking::Global<SensitiveGetQueryConfig>;
|
||||
|
||||
from SensitiveGetQueryFlow::PathNode source, SensitiveGetQueryFlow::PathNode sink
|
||||
where SensitiveGetQueryFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"$@ uses the GET request method to transmit sensitive information.", source.getNode(),
|
||||
"This request"
|
||||
|
||||
@@ -18,7 +18,7 @@ import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.frameworks.Servlets
|
||||
import semmle.code.xml.WebXML
|
||||
import DataFlow::PathGraph
|
||||
import UncaughtServletExceptionFlow::PathGraph
|
||||
|
||||
/** Holds if a given exception type is caught. */
|
||||
private predicate exceptionIsCaught(TryStmt t, RefType exType) {
|
||||
@@ -66,15 +66,15 @@ class UncaughtServletExceptionSink extends DataFlow::ExprNode {
|
||||
}
|
||||
|
||||
/** Taint configuration of uncaught exceptions caused by user provided data from `RemoteFlowSource` */
|
||||
class UncaughtServletExceptionConfiguration extends TaintTracking::Configuration {
|
||||
UncaughtServletExceptionConfiguration() { this = "UncaughtServletException" }
|
||||
module UncaughtServletExceptionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof UncaughtServletExceptionSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof UncaughtServletExceptionSink }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, UncaughtServletExceptionConfiguration c
|
||||
where c.hasFlowPath(source, sink) and not hasErrorPage()
|
||||
module UncaughtServletExceptionFlow = TaintTracking::Global<UncaughtServletExceptionConfig>;
|
||||
|
||||
from UncaughtServletExceptionFlow::PathNode source, UncaughtServletExceptionFlow::PathNode sink
|
||||
where UncaughtServletExceptionFlow::flowPath(source, sink) and not hasErrorPage()
|
||||
select sink.getNode(), source, sink, "This value depends on a $@ and can throw uncaught exception.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -15,7 +15,7 @@ import java
|
||||
import experimental.semmle.code.java.security.SpringUrlRedirect
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.controlflow.Guards
|
||||
import DataFlow::PathGraph
|
||||
import SpringUrlRedirectFlow::PathGraph
|
||||
|
||||
private predicate startsWithSanitizer(Guard g, Expr e, boolean branch) {
|
||||
g.(MethodAccess).getMethod().hasName("startsWith") and
|
||||
@@ -25,18 +25,16 @@ private predicate startsWithSanitizer(Guard g, Expr e, boolean branch) {
|
||||
branch = true
|
||||
}
|
||||
|
||||
class SpringUrlRedirectFlowConfig extends TaintTracking::Configuration {
|
||||
SpringUrlRedirectFlowConfig() { this = "SpringUrlRedirectFlowConfig" }
|
||||
module SpringUrlRedirectFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof SpringUrlRedirectSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof SpringUrlRedirectSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
springUrlRedirectTaintStep(fromNode, toNode)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
// Exclude the case where the left side of the concatenated string is not `redirect:`.
|
||||
// E.g: `String url = "/path?token=" + request.getParameter("token");`
|
||||
// Note this is quite a broad sanitizer (it will also sanitize the right-hand side of `url = "http://" + request.getParameter("token")`);
|
||||
@@ -62,7 +60,9 @@ class SpringUrlRedirectFlowConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, SpringUrlRedirectFlowConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module SpringUrlRedirectFlow = TaintTracking::Global<SpringUrlRedirectFlowConfig>;
|
||||
|
||||
from SpringUrlRedirectFlow::PathNode source, SpringUrlRedirectFlow::PathNode sink
|
||||
where SpringUrlRedirectFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Potentially untrusted URL redirection due to $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -14,18 +14,19 @@
|
||||
|
||||
import java
|
||||
import XXELib
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
import XxeFlow::PathGraph
|
||||
|
||||
class XxeConfig extends TaintTracking::Configuration {
|
||||
XxeConfig() { this = "XxeConfig" }
|
||||
module XxeConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeXxeSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeXxeSink }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, XxeConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module XxeFlow = TaintTracking::Global<XxeConfig>;
|
||||
|
||||
from XxeFlow::PathNode source, XxeFlow::PathNode sink
|
||||
where XxeFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Unsafe parsing of XML file from $@.", source.getNode(),
|
||||
"user input"
|
||||
|
||||
@@ -52,9 +52,7 @@ class ValidatorValidate extends XmlParserCall {
|
||||
|
||||
override Expr getSink() { result = this.getArgument(0) }
|
||||
|
||||
override predicate isSafe() {
|
||||
exists(SafeValidatorFlowConfig svfc | svfc.hasFlowToExpr(this.getQualifier()))
|
||||
}
|
||||
override predicate isSafe() { SafeValidatorFlow::flowToExpr(this.getQualifier()) }
|
||||
}
|
||||
|
||||
/** A `ParserConfig` specific to `Validator`. */
|
||||
@@ -82,21 +80,21 @@ class SafeValidator extends VarAccess {
|
||||
}
|
||||
}
|
||||
|
||||
private class SafeValidatorFlowConfig extends DataFlow3::Configuration {
|
||||
SafeValidatorFlowConfig() { this = "SafeValidatorFlowConfig" }
|
||||
private module SafeValidatorFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeValidator }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeValidator }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
sink.asExpr() = ma.getQualifier() and
|
||||
ma.getMethod().getDeclaringType() instanceof Validator
|
||||
)
|
||||
}
|
||||
|
||||
override int fieldFlowBranchLimit() { result = 0 }
|
||||
int fieldFlowBranchLimit() { result = 0 }
|
||||
}
|
||||
|
||||
private module SafeValidatorFlow = DataFlow::Global<SafeValidatorFlowConfig>;
|
||||
|
||||
/**
|
||||
* The classes `org.apache.commons.digester3.Digester`, `org.apache.commons.digester.Digester` or `org.apache.tomcat.util.digester.Digester`.
|
||||
*/
|
||||
@@ -121,9 +119,7 @@ class DigesterParse extends XmlParserCall {
|
||||
|
||||
override Expr getSink() { result = this.getArgument(0) }
|
||||
|
||||
override predicate isSafe() {
|
||||
exists(SafeDigesterFlowConfig sdfc | sdfc.hasFlowToExpr(this.getQualifier()))
|
||||
}
|
||||
override predicate isSafe() { SafeDigesterFlow::flowToExpr(this.getQualifier()) }
|
||||
}
|
||||
|
||||
/** A `ParserConfig` that is specific to `Digester`. */
|
||||
@@ -170,20 +166,20 @@ class SafeDigester extends VarAccess {
|
||||
}
|
||||
}
|
||||
|
||||
private class SafeDigesterFlowConfig extends DataFlow4::Configuration {
|
||||
SafeDigesterFlowConfig() { this = "SafeDigesterFlowConfig" }
|
||||
private module SafeDigesterFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeDigester }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeDigester }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
sink.asExpr() = ma.getQualifier() and ma.getMethod().getDeclaringType() instanceof Digester
|
||||
)
|
||||
}
|
||||
|
||||
override int fieldFlowBranchLimit() { result = 0 }
|
||||
int fieldFlowBranchLimit() { result = 0 }
|
||||
}
|
||||
|
||||
private module SafeDigesterFlow = DataFlow::Global<SafeDigesterFlowConfig>;
|
||||
|
||||
/** The class `java.beans.XMLDecoder`. */
|
||||
class XmlDecoder extends RefType {
|
||||
XmlDecoder() { this.hasQualifiedName("java.beans", "XMLDecoder") }
|
||||
|
||||
@@ -16,18 +16,19 @@
|
||||
|
||||
import java
|
||||
import XXELib
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
import XxeLocalFlow::PathGraph
|
||||
|
||||
class XxeLocalConfig extends TaintTracking::Configuration {
|
||||
XxeLocalConfig() { this = "XxeLocalConfig" }
|
||||
module XxeLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof LocalUserInput }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof LocalUserInput }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeXxeSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeXxeSink }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, XxeLocalConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module XxeLocalFlow = TaintTracking::Global<XxeLocalConfig>;
|
||||
|
||||
from XxeLocalFlow::PathNode source, XxeLocalFlow::PathNode sink
|
||||
where XxeLocalFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Unsafe parsing of XML file from $@.", source.getNode(),
|
||||
"user input"
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
import MatchRegexFlow::PathGraph
|
||||
import PermissiveDotRegexQuery
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, MatchRegexConfiguration conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from MatchRegexFlow::PathNode source, MatchRegexFlow::PathNode sink
|
||||
where MatchRegexFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Potentially authentication bypass due to $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -93,14 +93,12 @@ private class CompileRegexSink extends DataFlow::ExprNode {
|
||||
/**
|
||||
* A data flow configuration for regular expressions that include permissive dots.
|
||||
*/
|
||||
private class PermissiveDotRegexConfig extends DataFlow2::Configuration {
|
||||
PermissiveDotRegexConfig() { this = "PermissiveDotRegex::PermissiveDotRegexConfig" }
|
||||
private module PermissiveDotRegexConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow2::Node src) { src.asExpr() instanceof PermissiveDotStr }
|
||||
|
||||
override predicate isSource(DataFlow2::Node src) { src.asExpr() instanceof PermissiveDotStr }
|
||||
predicate isSink(DataFlow2::Node sink) { sink instanceof CompileRegexSink }
|
||||
|
||||
override predicate isSink(DataFlow2::Node sink) { sink instanceof CompileRegexSink }
|
||||
|
||||
override predicate isBarrier(DataFlow2::Node node) {
|
||||
predicate isBarrier(DataFlow2::Node node) {
|
||||
exists(
|
||||
MethodAccess ma, Field f // Pattern.compile(PATTERN, Pattern.DOTALL)
|
||||
|
|
||||
@@ -113,19 +111,19 @@ private class PermissiveDotRegexConfig extends DataFlow2::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
private module PermissiveDotRegexFlow = DataFlow::Global<PermissiveDotRegexConfig>;
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for untrusted user input used to match regular expressions
|
||||
* that include permissive dots.
|
||||
*/
|
||||
class MatchRegexConfiguration extends TaintTracking::Configuration {
|
||||
MatchRegexConfiguration() { this = "PermissiveDotRegex::MatchRegexConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module MatchRegexConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
sourceNode(source, "uri-path") or // Servlet uri source
|
||||
source instanceof SpringUriInputParameterSource // Spring uri source
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof MatchRegexSink and
|
||||
exists(
|
||||
Guard guard, Expr se, Expr ce // used in a condition to control url redirect, which is a typical security enforcement
|
||||
@@ -145,7 +143,7 @@ class MatchRegexConfiguration extends TaintTracking::Configuration {
|
||||
) and
|
||||
guard.controls(se.getBasicBlock(), true)
|
||||
) and
|
||||
exists(MethodAccess ma | any(PermissiveDotRegexConfig conf2).hasFlowToExpr(ma.getArgument(0)) |
|
||||
exists(MethodAccess ma | PermissiveDotRegexFlow::flowToExpr(ma.getArgument(0)) |
|
||||
// input.matches(regexPattern)
|
||||
ma.getMethod() instanceof StringMatchMethod and
|
||||
ma.getQualifier() = sink.asExpr()
|
||||
@@ -165,6 +163,8 @@ class MatchRegexConfiguration extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
module MatchRegexFlow = TaintTracking::Global<MatchRegexConfig>;
|
||||
|
||||
/**
|
||||
* A data flow sink representing a string being matched against a regular expression.
|
||||
*/
|
||||
|
||||
@@ -14,17 +14,15 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import XQueryInjectionLib
|
||||
import DataFlow::PathGraph
|
||||
import XQueryInjectionFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration tracing flow from remote sources, through an XQuery parser, to its eventual execution.
|
||||
*/
|
||||
class XQueryInjectionConfig extends TaintTracking::Configuration {
|
||||
XQueryInjectionConfig() { this = "XQueryInjectionConfig" }
|
||||
module XQueryInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(XQueryPreparedExecuteCall xpec).getPreparedExpression() or
|
||||
sink.asExpr() = any(XQueryExecuteCall xec).getExecuteQueryArgument() or
|
||||
sink.asExpr() = any(XQueryExecuteCommandCall xecc).getExecuteCommandArgument()
|
||||
@@ -33,12 +31,17 @@ class XQueryInjectionConfig extends TaintTracking::Configuration {
|
||||
/**
|
||||
* Holds if taint from the input `pred` to a `prepareExpression` call flows to the returned prepared expression `succ`.
|
||||
*/
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(XQueryParserCall parser | pred.asExpr() = parser.getInput() and succ.asExpr() = parser)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, XQueryInjectionConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
/**
|
||||
* Taint-tracking flow from remote sources, through an XQuery parser, to its eventual execution.
|
||||
*/
|
||||
module XQueryInjectionFlow = TaintTracking::Global<XQueryInjectionConfig>;
|
||||
|
||||
from XQueryInjectionFlow::PathNode source, XQueryInjectionFlow::PathNode sink
|
||||
where XQueryInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "XQuery query might include code from $@.", source.getNode(),
|
||||
"this user input"
|
||||
|
||||
@@ -32,12 +32,10 @@ predicate isRmiOrJmxServerCreateMethod(Method method) {
|
||||
* `map.put("jmx.remote.rmi.server.credential.types", value)` call
|
||||
* to an RMI or JMX initialisation call.
|
||||
*/
|
||||
class SafeFlow extends DataFlow::Configuration {
|
||||
SafeFlow() { this = "MapToPutCredentialstypeConfiguration" }
|
||||
module SafeFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { putsCredentialtypesKey(source.asExpr()) }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { putsCredentialtypesKey(source.asExpr()) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(Call c |
|
||||
isRmiOrJmxServerCreateConstructor(c.getCallee()) or
|
||||
isRmiOrJmxServerCreateMethod(c.getCallee())
|
||||
@@ -71,6 +69,8 @@ class SafeFlow extends DataFlow::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
module SafeFlow = DataFlow::Global<SafeFlowConfig>;
|
||||
|
||||
/** Gets a string describing why the application is vulnerable, depending on if the vulnerability is present due to a) a null environment b) an insecurely set environment map */
|
||||
string getRmiResult(Expr e) {
|
||||
// We got a Map so we have a source and a sink node
|
||||
@@ -87,5 +87,5 @@ from Call c, Expr envArg
|
||||
where
|
||||
(isRmiOrJmxServerCreateConstructor(c.getCallee()) or isRmiOrJmxServerCreateMethod(c.getCallee())) and
|
||||
envArg = c.getArgument(1) and
|
||||
not any(SafeFlow conf).hasFlowToExpr(envArg)
|
||||
not SafeFlow::flowToExpr(envArg)
|
||||
select c, getRmiResult(envArg), envArg, envArg.toString()
|
||||
|
||||
@@ -17,19 +17,17 @@ import java
|
||||
import semmle.code.java.frameworks.android.Intent
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.NumberFormatException
|
||||
import DataFlow::PathGraph
|
||||
import NfeLocalDoSFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Taint configuration tracking flow from untrusted inputs to number conversion calls in exported Android compononents.
|
||||
*/
|
||||
class NfeLocalDoSConfiguration extends TaintTracking::Configuration {
|
||||
NfeLocalDoSConfiguration() { this = "NFELocalDoSConfiguration" }
|
||||
|
||||
module NfeLocalDoSConfig implements DataFlow::ConfigSig {
|
||||
/** Holds if source is a remote flow source */
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
/** Holds if NFE is thrown but not caught */
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(Expr e |
|
||||
e.getEnclosingCallable().getDeclaringType().(ExportableAndroidComponent).isExported() and
|
||||
throwsNfe(e) and
|
||||
@@ -42,8 +40,10 @@ class NfeLocalDoSConfiguration extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, NfeLocalDoSConfiguration conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module NfeLocalDoSFlow = TaintTracking::Global<NfeLocalDoSConfig>;
|
||||
|
||||
from NfeLocalDoSFlow::PathNode source, NfeLocalDoSFlow::PathNode sink
|
||||
where NfeLocalDoSFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"Uncaught NumberFormatException in an exported Android component due to $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import DataFlow::PathGraph
|
||||
import HashWithoutSaltFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Gets a regular expression for matching common names of variables
|
||||
@@ -138,12 +138,10 @@ class HashWithoutSaltSink extends DataFlow::ExprNode {
|
||||
* 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) { sink instanceof HashWithoutSaltSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof HashWithoutSaltSink }
|
||||
|
||||
/**
|
||||
* Holds if a password is concatenated with a salt then hashed together through the call `System.arraycopy(password.getBytes(), ...)`, for example,
|
||||
@@ -152,7 +150,7 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
|
||||
* `byte[] messageDigest = md.digest(allBytes);`
|
||||
* Or the password is concatenated with a salt as a string.
|
||||
*/
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod().getDeclaringType().hasQualifiedName("java.lang", "System") and
|
||||
ma.getMethod().hasName("arraycopy") and
|
||||
@@ -176,6 +174,8 @@ class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, HashWithoutSaltConfiguration cc
|
||||
where cc.hasFlowPath(source, sink)
|
||||
module HashWithoutSaltFlow = TaintTracking::Global<HashWithoutSaltConfig>;
|
||||
|
||||
from HashWithoutSaltFlow::PathNode source, HashWithoutSaltFlow::PathNode sink
|
||||
where HashWithoutSaltFlow::flowPath(source, sink)
|
||||
select sink, source, sink, "$@ is hashed without a salt.", source, "The password"
|
||||
|
||||
@@ -1,53 +1,26 @@
|
||||
edges
|
||||
| JsonpController.java:33:32:33:68 | getParameter(...) : String | JsonpController.java:37:16:37:24 | resultStr |
|
||||
| JsonpController.java:36:21:36:54 | ... + ... : String | JsonpController.java:37:16:37:24 | resultStr |
|
||||
| JsonpController.java:44:32:44:68 | getParameter(...) : String | JsonpController.java:46:16:46:24 | resultStr |
|
||||
| JsonpController.java:45:21:45:80 | ... + ... : String | JsonpController.java:46:16:46:24 | resultStr |
|
||||
| JsonpController.java:53:32:53:68 | getParameter(...) : String | JsonpController.java:56:16:56:24 | resultStr |
|
||||
| JsonpController.java:55:21:55:55 | ... + ... : String | JsonpController.java:56:16:56:24 | resultStr |
|
||||
| JsonpController.java:63:32:63:68 | getParameter(...) : String | JsonpController.java:66:16:66:24 | resultStr |
|
||||
| JsonpController.java:65:21:65:54 | ... + ... : String | JsonpController.java:66:16:66:24 | resultStr |
|
||||
| JsonpController.java:73:32:73:68 | getParameter(...) : String | JsonpController.java:80:20:80:28 | resultStr |
|
||||
| JsonpController.java:79:21:79:54 | ... + ... : String | JsonpController.java:80:20:80:28 | resultStr |
|
||||
| JsonpController.java:87:32:87:68 | getParameter(...) : String | JsonpController.java:94:20:94:28 | resultStr |
|
||||
| JsonpController.java:93:21:93:54 | ... + ... : String | JsonpController.java:94:20:94:28 | resultStr |
|
||||
| JsonpController.java:101:32:101:68 | getParameter(...) : String | JsonpController.java:105:16:105:24 | resultStr |
|
||||
| JsonpController.java:104:21:104:54 | ... + ... : String | JsonpController.java:105:16:105:24 | resultStr |
|
||||
| JsonpController.java:115:21:115:54 | ... + ... : String | JsonpController.java:116:16:116:24 | resultStr |
|
||||
| JsonpController.java:130:21:130:54 | ... + ... : String | JsonpController.java:131:16:131:24 | resultStr |
|
||||
nodes
|
||||
| JsonpController.java:33:32:33:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:36:21:36:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:37:16:37:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:37:16:37:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:44:32:44:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:45:21:45:80 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:46:16:46:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:46:16:46:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:53:32:53:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:55:21:55:55 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:56:16:56:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:56:16:56:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:63:32:63:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:65:21:65:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:66:16:66:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:66:16:66:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:73:32:73:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:79:21:79:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:80:20:80:28 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:80:20:80:28 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:87:32:87:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:93:21:93:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:94:20:94:28 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:94:20:94:28 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:101:32:101:68 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JsonpController.java:104:21:104:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:105:16:105:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:105:16:105:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:115:21:115:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:116:16:116:24 | resultStr | semmle.label | resultStr |
|
||||
| JsonpController.java:130:21:130:54 | ... + ... : String | semmle.label | ... + ... : String |
|
||||
| JsonpController.java:131:16:131:24 | resultStr | semmle.label | resultStr |
|
||||
subpaths
|
||||
#select
|
||||
| JsonpController.java:37:16:37:24 | resultStr | JsonpController.java:33:32:33:68 | getParameter(...) : String | JsonpController.java:37:16:37:24 | resultStr | Jsonp response might include code from $@. | JsonpController.java:33:32:33:68 | getParameter(...) | this user input |
|
||||
|
||||
Reference in New Issue
Block a user