Python: Handle bound methods in flask modeling

This commit is contained in:
Rasmus Wriedt Larsen
2020-09-22 16:24:30 +02:00
parent 5709189c2a
commit 71a75ce596
2 changed files with 27 additions and 7 deletions

View File

@@ -5,6 +5,7 @@
private import python
private import experimental.dataflow.DataFlow
private import experimental.dataflow.RemoteFlowSources
private import experimental.dataflow.TaintTracking
private import experimental.semmle.python.Concepts
private import experimental.semmle.python.frameworks.Werkzeug
@@ -50,6 +51,20 @@ private module Flask {
override string getSourceType() { result = "flask.request" }
}
private module FlaskRequestTracking {
private DataFlow::Node tainted_methods(string attr_name, DataFlow::TypeTracker t) {
attr_name in ["get_data", "get_json"] and
t.startInAttr(attr_name) and
result = flask::request()
or
exists(DataFlow::TypeTracker t2 | result = tainted_methods(attr_name, t2).track(t2, t))
}
DataFlow::Node tainted_methods(string attr_name) {
result = tainted_methods(attr_name, DataFlow::TypeTracker::end())
}
}
/**
* A source of remote flow from attributes from a flask request.
*
@@ -99,17 +114,22 @@ private module Flask {
"headers"]
)
or
// methods
exists(CallNode call | this.asCfgNode() = call |
// NOTE: will not track bound method, `f = obj.func; f()`
attr_name in ["get_data", "get_json"] and
call.getFunction().(AttrNode).getObject(attr_name) = flask::request().asCfgNode()
)
// methods (needs special handling to track bound-methods -- see `FlaskRequestMethodCallsAdditionalTaintStep` below)
this = FlaskRequestTracking::tainted_methods(attr_name)
}
override string getSourceType() { result = "flask.request input" }
}
private class FlaskRequestMethodCallsAdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// NOTE: `request -> request.tainted_method` part is handled as part of RequestInputAccess
// tainted_method -> tainted_method()
nodeFrom = FlaskRequestTracking::tainted_methods(_) and
nodeTo.asCfgNode().(CallNode).getFunction() = nodeFrom.asCfgNode()
}
}
private class RequestInputMultiDict extends RequestInputAccess,
Werkzeug::Datastructures::MultiDict {
RequestInputMultiDict() { attr_name in ["args", "values", "form", "files"] }

View File

@@ -95,4 +95,4 @@
| test.py:179 | ok | test_taint | b.getlist(..) |
| test.py:180 | ok | test_taint | gl(..) |
| test.py:187 | ok | test_taint | req.path |
| test.py:188 | fail | test_taint | gd() |
| test.py:188 | ok | test_taint | gd() |