JS: Propagate into RegExp.$x

This commit is contained in:
Asger Feldthaus
2020-06-25 17:09:27 +01:00
parent 17af8f7650
commit 06dd3ab2ca
3 changed files with 73 additions and 3 deletions

View File

@@ -705,6 +705,68 @@ module TaintTracking {
}
}
private module RegExpCaptureSteps {
/** Gets a reference to a string derived from the most recent RegExp match, such as `RegExp.$1` */
private DataFlow::PropRead getAStaticCaptureRef() {
result =
DataFlow::globalVarRef("RegExp")
.getAPropertyRead(["$" + [1 .. 9], "input", "lastMatch", "leftContext", "rightContext",
"$&", "$^", "$`"])
}
/**
* Gets a control-flow node where `input` is used in a RegExp match.
*/
private ControlFlowNode getACaptureSetter(DataFlow::Node input) {
exists(DataFlow::MethodCallNode call | result = call.asExpr() |
call.getMethodName() = ["search", "replace", "match"] and input = call.getReceiver()
or
call.getMethodName() = ["test", "exec"] and input = call.getArgument(0)
)
}
/**
* Gets a control-flow node that can locally reach the given static capture reference
* without passing through a capture setter.
*
* This is essentially an intraprocedural def-use analysis that ignores potential
* side effects from calls.
*/
private ControlFlowNode getANodeReachingCaptureRef(DataFlow::PropRead read) {
result = read.asExpr() and
read = getAStaticCaptureRef()
or
exists(ControlFlowNode mid |
mid = getANodeReachingCaptureRef(read) and
not mid = getACaptureSetter(_) and
result = mid.getAPredecessor()
)
}
/**
* Holds if there is a step `pred -> succ` from the input of a RegExp match to
* a static property of `RegExp` defined.
*/
private predicate staticRegExpCaptureStep(DataFlow::Node pred, DataFlow::Node succ) {
getACaptureSetter(pred) = getANodeReachingCaptureRef(succ)
or
exists(DataFlow::MethodCallNode replace |
replace.getMethodName() = "replace" and
getANodeReachingCaptureRef(succ) = replace.getCallback(1).getFunction().getEntry() and
pred = replace.getReceiver()
)
}
private class StaticRegExpCaptureStep extends AdditionalTaintStep {
StaticRegExpCaptureStep() { staticRegExpCaptureStep(this, _) }
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
pred = this and
staticRegExpCaptureStep(this, succ)
}
}
}
/**
* A conditional checking a tainted string against a regular expression, which is
* considered to be a sanitizer for all configurations.