mirror of
https://github.com/github/codeql.git
synced 2026-05-20 22:27:18 +02:00
add CodeInjection extraction and evaluation queries
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for reasoning about code
|
||||
* injection vulnerabilities.
|
||||
*
|
||||
* Note, for performance reasons: only import this file if
|
||||
* `CodeInjection::Configuration` is needed, otherwise
|
||||
* `CodeInjectionCustomizations` should be imported instead.
|
||||
* Is boosted by ATM.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import AdaptiveThreatModeling
|
||||
import semmle.javascript.security.dataflow.CodeInjectionCustomizations::CodeInjection
|
||||
|
||||
/**
|
||||
* 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 CodeInjectionATMConfig extends ATMConfig {
|
||||
CodeInjectionATMConfig() { this = "CodeInjectionATMConfig" }
|
||||
|
||||
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 CodeInjectionSinkType }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about code injection vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "CodeInjectionATMConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
(sink instanceof Sink or any(CodeInjectionATMConfig cfg).isEffectiveSink(sink))
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof Sanitizer
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node trg) {
|
||||
// HTML sanitizers are insufficient protection against code injection
|
||||
src = trg.(HtmlSanitizerCall).getInput()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* CodeInjection.ql
|
||||
*
|
||||
* Version of the standard Code Injection query with an output relation ready to plug into the evaluation
|
||||
* pipeline.
|
||||
*
|
||||
* Standard query: javascript/ql/src/Security/CWE-094/CodeInjection.ql
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.CodeInjectionQuery
|
||||
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
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* CodeInjectionATM.ql
|
||||
*
|
||||
* Version of the boosted Code Injection query with an output relation ready to plug into the evaluation
|
||||
* pipeline.
|
||||
*/
|
||||
|
||||
import ATM::ResultsInfo
|
||||
import EndToEndEvaluation as EndToEndEvaluation
|
||||
import experimental.adaptivethreatmodeling.CodeInjectionATM
|
||||
|
||||
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
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* CodeInjectionATMLite.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.CodeInjectionATM
|
||||
|
||||
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
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* For internal use only.
|
||||
*
|
||||
* @name Code injection (boosted)
|
||||
* @description Interpreting unsanitized user input as code allows a malicious user arbitrary code execution.
|
||||
* @kind path-problem
|
||||
* @scored
|
||||
* @problem.severity error
|
||||
* @security-severity 9.3
|
||||
* @id adaptive-threat-modeling/js/code-injection
|
||||
* @tags experimental experimental/atm security external/cwe/cwe-094 external/cwe/cwe-095 external/cwe/cwe-079 external/cwe/cwe-116
|
||||
*/
|
||||
|
||||
import experimental.adaptivethreatmodeling.CodeInjectionATM
|
||||
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/code-injection result depending on $@ " +
|
||||
getAdditionalAlertInfo(source.getNode(), sink.getNode()), source.getNode(),
|
||||
"a user-provided value", score
|
||||
Reference in New Issue
Block a user