Compare commits

...

3 Commits

Author SHA1 Message Date
annarailton
a047b63220 Add boosted and unboosted evaluation versions of StoredXss and XssThroughDom 2022-02-28 16:25:33 +00:00
annarailton
da3826f85a Add ATMLite versions of StoredXss and XssThroughDom 2022-02-28 15:34:48 +00:00
Esben Sparre Andreasen
66ea3a1548 Boost StoredXss and XssThroughDomATM
Produced with:
```
javascript/ql$tb boost src/Security/CWE-079/StoredXss.ql XssSink
javascript/ql$ tb boost src/Security/CWE-079/XssThroughDom.ql XssSink
```
2022-02-28 15:34:10 +00:00
10 changed files with 370 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
/**
* Provides a taint-tracking configuration for reasoning about stored
* cross-site scripting vulnerabilities.
* Is boosted by ATM.
*/
import javascript
import AdaptiveThreatModeling
import semmle.javascript.security.dataflow.Xss::StoredXss
/**
* 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 StoredXssATMConfig extends ATMConfig {
StoredXssATMConfig() { this = "StoredXssATMConfig" }
override predicate isKnownSource(DataFlow::Node source) { source instanceof Source }
override predicate isKnownSink(DataFlow::Node sink) { sink instanceof 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.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "StoredXssATMConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) {
(sink instanceof Sink or any(StoredXssATMConfig cfg).isEffectiveSink(sink))
}
override predicate isSanitizer(DataFlow::Node node) {
super.isSanitizer(node) or
node instanceof Sanitizer
}
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
guard instanceof SanitizerGuard
}
}
/** A file name, considered as a flow source for stored XSS. */
class FileNameSourceAsSource extends Source {
FileNameSourceAsSource() { this instanceof FileNameSource }
}
/** An instance of user-controlled torrent information, considered as a flow source for stored XSS. */
class UserControlledTorrentInfoAsSource extends Source {
UserControlledTorrentInfoAsSource() { this instanceof ParseTorrent::UserControlledTorrentInfo }
}

View File

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

View File

@@ -0,0 +1,26 @@
/**
* Xss.ql
*
* Version of the standard stored XSS query with an output relation ready to plug into the evaluation
* pipeline.
*
* Standard query: javascript/ql/src/Security/CWE-079/StoredXss.ql
*/
import semmle.javascript.security.dataflow.StoredXssQuery
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

View File

@@ -0,0 +1,28 @@
/**
* XssATM.ql
*
* Version of the boosted stored XSS query with an output relation ready to plug into the evaluation
* pipeline.
*/
import ATM::ResultsInfo
import EndToEndEvaluation as EndToEndEvaluation
import experimental.adaptivethreatmodeling.StoredXssATM
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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,29 @@
/**
* For internal use only.
*
* @name Stored cross-site scripting (boosted)
* @description Using uncontrolled stored values in HTML allows for a stored cross-site scripting vulnerability.
* @kind path-problem
* @scored
* @problem.severity error
* @security-severity 6.1
* @id adaptive-threat-modeling/js/stored-xss
* @tags experimental experimental/atm security external/cwe/cwe-079 external/cwe/cwe-116
*/
import experimental.adaptivethreatmodeling.StoredXssATM
import ATM::ResultsInfo
import DataFlow::PathGraph
from
DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, float score,
string scoreString
where
cfg.hasFlowPath(source, sink) and
not isFlowLikelyInBaseQuery(source.getNode(), sink.getNode()) and
score = getScoreForFlow(source.getNode(), sink.getNode()) and
scoreString = getScoreStringForFlow(source.getNode(), sink.getNode())
select sink.getNode(), source, sink,
"[Score = " + scoreString + "] This may be a js/stored-xss result depending on $@ " +
getAdditionalAlertInfo(source.getNode(), sink.getNode()), source.getNode(),
"a user-provided value", score

View File

@@ -0,0 +1,29 @@
/**
* For internal use only.
*
* @name DOM text reinterpreted as HTML (boosted)
* @description Reinterpreting text from the DOM as HTML can lead to a cross-site scripting vulnerability.
* @kind path-problem
* @scored
* @problem.severity warning
* @security-severity 6.1
* @id adaptive-threat-modeling/js/xss-through-dom
* @tags experimental experimental/atm security external/cwe/cwe-079 external/cwe/cwe-116
*/
import experimental.adaptivethreatmodeling.XssThroughDomATM
import ATM::ResultsInfo
import DataFlow::PathGraph
from
DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, float score,
string scoreString
where
cfg.hasFlowPath(source, sink) and
not isFlowLikelyInBaseQuery(source.getNode(), sink.getNode()) and
score = getScoreForFlow(source.getNode(), sink.getNode()) and
scoreString = getScoreStringForFlow(source.getNode(), sink.getNode())
select sink.getNode(), source, sink,
"[Score = " + scoreString + "] This may be a js/xss-through-dom result depending on $@ " +
getAdditionalAlertInfo(source.getNode(), sink.getNode()), source.getNode(),
"a user-provided value", score