Compare commits

...

6 Commits

Author SHA1 Message Date
tiferet
bd8c9edb67 ATM model for a DCA experiment
New features: Shipping model. 9 new features, remove the old ones that have been replaced by new ones. The codeql PR has been rebased on top of main. #7 (with a fixed package version)

https://ml.azure.com/runs/classification_1663364335_afeafbe1?wsid=/subscriptions/91095667-e119-4555-acea-1826488492f0/resourcegroups/ATM-CodeML/workspaces/ATM-Workspace&tid=398a6654-997b-47e9-b12b-9515b896b4de
2022-11-22 15:22:24 +01:00
Jean Helie
8334618545 Merge branch 'main' into jhelie/add-xss-through-dom 2022-11-10 17:13:30 +01:00
Jean Helie
227d6fffa7 Merge branch 'jhelie/add-xss-through-dom' of github.com:github/codeql into jhelie/add-xss-through-dom 2022-11-10 16:51:52 +01:00
Jean Helie
38430c57a2 ATM: update query sink mapping 2022-11-10 16:51:40 +01:00
Jean Helie
98379d3c12 Merge branch 'main' into jhelie/add-xss-through-dom 2022-11-10 16:13:36 +01:00
Jean Helie
01163bc618 ATM: add XSSThroughDOM boosted query 2022-11-10 14:29:55 +01:00
5 changed files with 189 additions and 3 deletions

View File

@@ -0,0 +1,154 @@
/**
* For internal use only.
*
* Defines shared code used by the XSS Through DOM boosted query.
*/
private import semmle.javascript.heuristics.SyntacticHeuristics
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
private import semmle.javascript.dataflow.InferredTypes
private import semmle.javascript.security.dataflow.XssThroughDomCustomizations::XssThroughDom as XssThroughDom
private import semmle.javascript.security.dataflow.UnsafeJQueryPluginCustomizations::UnsafeJQueryPlugin as UnsafeJQuery
import AdaptiveThreatModeling
import CoreKnowledge as CoreKnowledge
import StandardEndpointFilters as StandardEndpointFilters
/**
* This module provides logic to filter candidate sinks to those which are likely XSS sinks.
*/
module SinkEndpointFilter {
/**
* 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)
or
exists(DataFlow::CallNode call | sinkCandidate = call.getAnArgument() |
call.getCalleeName() = "setState"
) and
result = "setState calls ought to be safe in react applications"
or
// Require XSS sink candidates to be (a) arguments to external library calls (possibly
// indirectly), or (b) heuristic sinks.
//
// Heuristic sinks are copied from the `HeuristicDomBasedXssSink` class defined within
// `codeql/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll`.
// We can't reuse the class because importing that file would cause us to treat these
// heuristic sinks as known sinks.
not StandardEndpointFilters::flowsToArgumentOfLikelyExternalLibraryCall(sinkCandidate) and
not (
isAssignedToOrConcatenatedWith(sinkCandidate, "(?i)(html|innerhtml)")
or
isArgTo(sinkCandidate, "(?i)(html|render)")
or
sinkCandidate instanceof StringOps::HtmlConcatenationLeaf
or
isConcatenatedWithStrings("(?is).*<[a-z ]+.*", sinkCandidate, "(?s).*>.*")
or
// In addition to the heuristic sinks from `HeuristicDomBasedXssSink`, explicitly allow
// property writes like `elem.innerHTML = <TAINT>` that may not be picked up as HTML
// concatenation leaves.
exists(DataFlow::PropWrite pw |
pw.getPropertyName().regexpMatch("(?i).*html*") and
pw.getRhs() = sinkCandidate
)
) and
result = "not a direct argument to a likely external library call or a heuristic sink"
}
}
class XssThroughDomAtmConfig extends AtmConfig {
XssThroughDomAtmConfig() { this = "XssThroughDomAtmConfig" }
override predicate isKnownSource(DataFlow::Node source) {
source instanceof XssThroughDom::Source
}
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 XssThroughDom::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 UnsafeJQuery::NumberGuard or
guard instanceof PrefixStringSanitizer or
guard instanceof QuoteGuard or
guard instanceof ContainsHtmlGuard
}
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
DomBasedXss::isOptionallySanitizedEdge(pred, succ)
}
}
/**
* A test of form `typeof x === "something"`, preventing `x` from being a string in some cases.
*
* This sanitizer helps prune infeasible paths in type-overloaded functions.
*/
class TypeTestGuard extends TaintTracking::SanitizerGuardNode, DataFlow::ValueNode {
override EqualityTest astNode;
Expr operand;
boolean polarity;
TypeTestGuard() {
exists(TypeofTag tag | TaintTracking::isTypeofGuard(astNode, operand, tag) |
// typeof x === "string" sanitizes `x` when it evaluates to false
tag = "string" and
polarity = astNode.getPolarity().booleanNot()
or
// typeof x === "object" sanitizes `x` when it evaluates to true
tag != "string" and
polarity = astNode.getPolarity()
)
}
override predicate sanitizes(boolean outcome, Expr e) {
polarity = outcome and
e = operand
}
}
private import semmle.javascript.security.dataflow.Xss::Shared as Shared
private class PrefixStringSanitizer extends TaintTracking::SanitizerGuardNode,
DomBasedXss::PrefixStringSanitizer {
PrefixStringSanitizer() { this = this }
}
private class PrefixString extends DataFlow::FlowLabel, DomBasedXss::PrefixString {
PrefixString() { this = this }
}
private class QuoteGuard extends TaintTracking::SanitizerGuardNode, Shared::QuoteGuard {
QuoteGuard() { this = this }
}
private class ContainsHtmlGuard extends TaintTracking::SanitizerGuardNode, Shared::ContainsHtmlGuard {
ContainsHtmlGuard() { this = this }
}

View File

@@ -8,6 +8,7 @@ import experimental.adaptivethreatmodeling.SqlInjectionATM as SqlInjectionAtm
import experimental.adaptivethreatmodeling.NosqlInjectionATM as NosqlInjectionAtm
import experimental.adaptivethreatmodeling.TaintedPathATM as TaintedPathAtm
import experimental.adaptivethreatmodeling.XssATM as XssAtm
import experimental.adaptivethreatmodeling.XssThroughDomATM as XssThroughDomAtm
import experimental.adaptivethreatmodeling.AdaptiveThreatModeling
from string queryName, AtmConfig c, EndpointType e
@@ -23,6 +24,8 @@ where
c instanceof TaintedPathAtm::TaintedPathAtmConfig
or
queryName = "Xss" and c instanceof XssAtm::DomBasedXssAtmConfig
or
queryName = "XssThroughDOM" and c instanceof XssThroughDomAtm::XssThroughDomAtmConfig
) and
e = c.getASinkEndpointType()
select queryName, e.getEncoding() as label

View File

@@ -0,0 +1,29 @@
/**
* For internal use only.
*
* @name DOM text reinterpreted as HTML (experimental)
* @description Reinterpreting text from the DOM as HTML can lead
* to a cross-site scripting vulnerability.
* @kind path-problem
* @scored
* @problem.severity error
* @security-severity 6.1
* @id js/ml-powered/xss-through-dom
* @tags experimental security
* external/cwe/cwe-079 external/cwe/cwe-116
*/
import javascript
import ATM::ResultsInfo
import DataFlow::PathGraph
import experimental.adaptivethreatmodeling.XssThroughDomATM
from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, float score
where
cfg.hasFlowPath(source, sink) and
not isFlowLikelyInBaseQuery(source.getNode(), sink.getNode()) and
score = getScoreForFlow(source.getNode(), sink.getNode()) and
score = getScoreForFlow(source.getNode(), sink.getNode())
select sink.getNode(), source, sink,
"(Experimental) $@ may be reinterpreted as HTML without escaping meta-characters. Identified using machine learning.",
source.getNode(), "DOM text", score

View File

@@ -1,6 +1,6 @@
---
dependencies:
codeql/javascript-experimental-atm-model:
version: 0.3.0
dsp-testing/javascript-experimental-atm-model:
version: 0.2.1-2022-09-16-14h38m47s.willing-ocean-d4l9xjl1.67c0d6cefb42f08d9f177ffaebb9af8efa741d41af8fb682d0b545ca39866c04
compiled: false
lockVersion: 1.0.0

View File

@@ -8,4 +8,4 @@ groups:
- experimental
dependencies:
codeql/javascript-experimental-atm-lib: ${workspace}
codeql/javascript-experimental-atm-model: "0.3.0"
dsp-testing/javascript-experimental-atm-model: 0.2.1-2022-09-16-14h38m47s.willing-ocean-d4l9xjl1.67c0d6cefb42f08d9f177ffaebb9af8efa741d41af8fb682d0b545ca39866c04