diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/XssThroughDomATM.qll b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/XssThroughDomATM.qll new file mode 100644 index 00000000000..603ccacf188 --- /dev/null +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/XssThroughDomATM.qll @@ -0,0 +1,72 @@ +/** + * Provides a taint-tracking configuration for reasoning about + * cross-site scripting vulnerabilities through the DOM. + * Is boosted by ATM. + */ + +import javascript +import AdaptiveThreatModeling +private import semmle.javascript.dataflow.InferredTypes +import semmle.javascript.security.dataflow.Xss::XssThroughDom +private import semmle.javascript.security.dataflow.XssThroughDomCustomizations::XssThroughDom +private import semmle.javascript.security.dataflow.Xss::DomBasedXss as DomBasedXss +private import semmle.javascript.security.dataflow.UnsafeJQueryPluginCustomizations::UnsafeJQueryPlugin as UnsafeJQuery + +/** + * This module provides logic to filter candidate sinks to those which are likely XSS sinks. + */ +module SinkEndpointFilter { + private import StandardEndpointFilters as StandardEndpointFilters + + /** + * Provides a set of reasons why a given data flow node should be excluded as a sink candidate. + * + * If this predicate has no results for a sink candidate `n`, then we should treat `n` as an + * effective sink. + */ + string getAReasonSinkExcluded(DataFlow::Node sinkCandidate) { + result = StandardEndpointFilters::getAReasonSinkExcluded(sinkCandidate) + } +} + +class XssThroughDomAtmConfig extends ATMConfig { + XssThroughDomAtmConfig() { this = "XssThroughDomAtmConfig" } + + override predicate isKnownSource(DataFlow::Node source) { source instanceof Source } + + override predicate isKnownSink(DataFlow::Node sink) { sink instanceof DomBasedXss::Sink } + + override predicate isEffectiveSink(DataFlow::Node sinkCandidate) { + not exists(SinkEndpointFilter::getAReasonSinkExcluded(sinkCandidate)) + } + + override EndpointType getASinkEndpointType() { result instanceof XssSinkType } +} + +/** + * A taint-tracking configuration for reasoning about XSS through the DOM. + */ +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "XssThroughDomAtmConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { + (sink instanceof DomBasedXss::Sink or any(XssThroughDomAtmConfig cfg).isEffectiveSink(sink)) + } + + override predicate isSanitizer(DataFlow::Node node) { + super.isSanitizer(node) or + node instanceof DomBasedXss::Sanitizer + } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof TypeTestGuard or + guard instanceof UnsafeJQuery::PropertyPresenceSanitizer or + guard instanceof DomBasedXss::SanitizerGuard + } + + override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) { + DomBasedXss::isOptionallySanitizedEdge(pred, succ) + } +} diff --git a/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/evaluation/XssThroughDom.ql b/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/evaluation/XssThroughDom.ql new file mode 100644 index 00000000000..406d8fa2234 --- /dev/null +++ b/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/evaluation/XssThroughDom.ql @@ -0,0 +1,26 @@ +/** + * XssThroughDom.ql + * + * Version of the standard XSS through DOM query with an output relation ready to plug into the evaluation + * pipeline. + * + * Standard query: javascript/ql/src/Security/CWE-079/XssThroughDom.ql + */ + +import semmle.javascript.security.dataflow.XssThroughDomQuery +import EndToEndEvaluation as EndToEndEvaluation + +from + DataFlow::Configuration cfg, DataFlow::Node source, DataFlow::Node sink, string filePathSink, + int startLineSink, int endLineSink, int startColumnSink, int endColumnSink, string filePathSource, + int startLineSource, int endLineSource, int startColumnSource, int endColumnSource +where + cfg instanceof Configuration and + cfg.hasFlow(source, sink) and + not EndToEndEvaluation::isFlowExcluded(source, sink) and + sink.hasLocationInfo(filePathSink, startLineSink, startColumnSink, endLineSink, endColumnSink) and + source + .hasLocationInfo(filePathSource, startLineSource, startColumnSource, endLineSource, + endColumnSource) +select source, startLineSource, startColumnSource, endLineSource, endColumnSource, filePathSource, + sink, startLineSink, startColumnSink, endLineSink, endColumnSink, filePathSink diff --git a/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/evaluation/XssThroughDomATM.ql b/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/evaluation/XssThroughDomATM.ql new file mode 100644 index 00000000000..5c7506619c8 --- /dev/null +++ b/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/evaluation/XssThroughDomATM.ql @@ -0,0 +1,28 @@ +/** + * XssATM.ql + * + * Version of the boosted XSS through DOM query with an output relation ready to plug into the evaluation + * pipeline. + */ + +import ATM::ResultsInfo +import EndToEndEvaluation as EndToEndEvaluation +import experimental.adaptivethreatmodeling.XssThroughDomATM + +from + DataFlow::Configuration cfg, DataFlow::Node source, DataFlow::Node sink, string filePathSink, + int startLineSink, int endLineSink, int startColumnSink, int endColumnSink, string filePathSource, + int startLineSource, int endLineSource, int startColumnSource, int endColumnSource, float score +where + cfg.hasFlow(source, sink) and + not EndToEndEvaluation::isFlowExcluded(source, sink) and + not isFlowLikelyInBaseQuery(source, sink) and + sink.hasLocationInfo(filePathSink, startLineSink, startColumnSink, endLineSink, endColumnSink) and + source + .hasLocationInfo(filePathSource, startLineSource, startColumnSource, endLineSource, + endColumnSource) and + getScoreForFlow(source, sink) = score +select source, startLineSource, startColumnSource, endLineSource, endColumnSource, filePathSource, + sink, startLineSink, startColumnSink, endLineSink, endColumnSink, filePathSink, score order by + score desc, startLineSource, startColumnSource, endLineSource, endColumnSource, filePathSource, + startLineSink, startColumnSink, endLineSink, endColumnSink, filePathSink diff --git a/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/evaluation/XssThroughDomATMLite.ql b/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/evaluation/XssThroughDomATMLite.ql new file mode 100644 index 00000000000..a679666ef22 --- /dev/null +++ b/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/evaluation/XssThroughDomATMLite.ql @@ -0,0 +1,30 @@ +/** + * XssATMLite.ql + * + * Arbitrarily ranked version of the boosted XSS query with an output relation ready to plug into + * the evaluation pipeline. This is useful (a) for evaluating the performance of endpoint filters, + * and (b) as a baseline to compare the model against. + */ + +import javascript +import ATM::ResultsInfo +import EndToEndEvaluation as EndToEndEvaluation +import experimental.adaptivethreatmodeling.XssThroughDomATM + +from + DataFlow::Configuration cfg, DataFlow::Node source, DataFlow::Node sink, string filePathSink, + int startLineSink, int endLineSink, int startColumnSink, int endColumnSink, string filePathSource, + int startLineSource, int endLineSource, int startColumnSource, int endColumnSource, float score +where + cfg.hasFlow(source, sink) and + not EndToEndEvaluation::isFlowExcluded(source, sink) and + not isFlowLikelyInBaseQuery(source, sink) and + sink.hasLocationInfo(filePathSink, startLineSink, startColumnSink, endLineSink, endColumnSink) and + source + .hasLocationInfo(filePathSource, startLineSource, startColumnSource, endLineSource, + endColumnSource) and + score = 0 +select source, startLineSource, startColumnSource, endLineSource, endColumnSource, filePathSource, + sink, startLineSink, startColumnSink, endLineSink, endColumnSink, filePathSink, score order by + score desc, startLineSource, startColumnSource, endLineSource, endColumnSource, filePathSource, + startLineSink, startColumnSink, endLineSink, endColumnSink, filePathSink