JavaScript: Teach PostMessageStar to reason about partially tainted objects.

This commit is contained in:
Max Schaefer
2019-01-31 08:59:47 +00:00
parent aeb8cc62b2
commit 87e62f0bd5
3 changed files with 66 additions and 2 deletions

View File

@@ -22,6 +22,20 @@ module PostMessageStar {
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* A flow label representing an object with at least one tainted property.
*/
private class PartiallyTaintedObject extends DataFlow::FlowLabel {
PartiallyTaintedObject() { this = "partially tainted object" }
}
/**
* Gets either a standard flow label or the partial-taint label.
*/
private DataFlow::FlowLabel anyLabel() {
result instanceof DataFlow::StandardFlowLabel or result instanceof PartiallyTaintedObject
}
/**
* A taint tracking configuration for cross-window communication with unrestricted origin.
*
@@ -38,9 +52,38 @@ module PostMessageStar {
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel lbl) {
sink instanceof Sink and lbl = anyLabel()
}
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
override predicate isAdditionalFlowStep(
DataFlow::Node src, DataFlow::Node trg, DataFlow::FlowLabel inlbl, DataFlow::FlowLabel outlbl
) {
// writing a tainted value to an object property makes the object partially tainted
exists(DataFlow::PropWrite write |
write.getRhs() = src and
inlbl = anyLabel() and
trg.(DataFlow::SourceNode).flowsTo(write.getBase()) and
outlbl instanceof PartiallyTaintedObject
)
or
// `toString` or `JSON.toString` on a partially tainted object gives a tainted value
exists (DataFlow::InvokeNode toString | toString = trg |
toString.(DataFlow::MethodCallNode).calls(src, "toString")
or
toString = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") and
src = toString.getArgument(0)
) and
inlbl instanceof PartiallyTaintedObject and
outlbl = DataFlow::FlowLabel::taint()
or
// `valueOf` preserves partial taint
trg.(DataFlow::MethodCallNode).calls(src, "valueOf") and
inlbl instanceof PartiallyTaintedObject and
outlbl = inlbl
}
}
/**