Rewrite frameworks modeling

This commit is contained in:
jorgectf
2021-06-18 02:03:27 +02:00
parent 066504e79e
commit 4963caf506
4 changed files with 186 additions and 0 deletions

View File

@@ -3,3 +3,6 @@
*/
private import experimental.semmle.python.frameworks.Stdlib
private import experimental.semmle.python.frameworks.Flask
private import experimental.semmle.python.frameworks.Django
private import experimental.semmle.python.frameworks.Werkzeug

View File

@@ -0,0 +1,78 @@
/**
* Provides classes modeling security-relevant aspects of the `django` PyPI package.
* See https://www.djangoproject.com/.
*/
private import python
private import semmle.python.frameworks.Django
private import semmle.python.dataflow.new.DataFlow
private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
private module PrivateDjango {
API::Node django() { result = API::moduleImport("django") }
private module django {
API::Node http() { result = django().getMember("http") }
module http {
API::Node response() { result = http().getMember("response") }
module response {
module HttpResponse {
API::Node baseClassRef() {
result = response().getMember("HttpResponse").getReturn()
or
// Handle `django.http.HttpResponse` alias
result = http().getMember("HttpResponse").getReturn()
}
/** Gets a reference to a header instance. */
private DataFlow::LocalSourceNode headerInstance(DataFlow::TypeTracker t) {
t.start() and
(
exists(SubscriptNode subscript |
subscript.getObject() = baseClassRef().getAUse().asCfgNode() and
result.asCfgNode() = subscript
)
or
result.(DataFlow::AttrRead).getObject() = baseClassRef().getAUse()
)
or
exists(DataFlow::TypeTracker t2 | result = headerInstance(t2).track(t2, t))
}
/** Gets a reference to a header instance use. */
private DataFlow::Node headerInstance() {
headerInstance(DataFlow::TypeTracker::end()).flowsTo(result)
}
/** Gets a reference to a header instance call with `__setitem__`. */
private DataFlow::Node headerSetItemCall() {
result = headerInstance() and
result.(DataFlow::AttrRead).getAttributeName() = "__setitem__"
}
class DjangoResponseSetItemCall extends DataFlow::CallCfgNode, HeaderDeclaration::Range {
DjangoResponseSetItemCall() { this.getFunction() = headerSetItemCall() }
override DataFlow::Node getHeaderInput() { result = this.getArg([0, 1]) }
}
class DjangoResponseDefinition extends DataFlow::Node, HeaderDeclaration::Range {
DataFlow::Node headerInput;
DjangoResponseDefinition() {
this.asCfgNode().(DefinitionNode) = headerInstance().asCfgNode() and
headerInput.asCfgNode() = this.asCfgNode().(DefinitionNode).getValue()
}
override DataFlow::Node getHeaderInput() {
result.asExpr() in [headerInput.asExpr(), this.asExpr().(Subscript).getIndex()]
}
}
}
}
}
}
}

View File

@@ -0,0 +1,74 @@
/**
* Provides classes modeling security-relevant aspects of the `flask` PyPI package.
* See https://flask.palletsprojects.com/en/1.1.x/.
*/
private import python
private import semmle.python.frameworks.Flask
private import semmle.python.dataflow.new.DataFlow
private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
module ExperimentalFlask {
/**
* A reference to either `flask.make_response` function, or the `make_response` method on
* an instance of `flask.Flask`. This creates an instance of the `flask_response`
* class (class-attribute on a flask application), which by default is
* `flask.Response`.
*
* See
* - https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.make_response
* - https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response
*/
private API::Node flaskMakeResponse() {
result in [
API::moduleImport("flask").getMember("make_response"),
Flask::FlaskApp::instance().getMember("make_response")
]
}
/** Gets a reference to a header instance. */
private DataFlow::LocalSourceNode headerInstance(DataFlow::TypeTracker t) {
t.start() and
result.(DataFlow::AttrRead).getObject().getALocalSource() =
[Flask::Response::classRef(), flaskMakeResponse()].getReturn().getAUse()
or
exists(DataFlow::TypeTracker t2 | result = headerInstance(t2).track(t2, t))
}
/** Gets a reference to a header instance use. */
private DataFlow::Node headerInstance() {
headerInstance(DataFlow::TypeTracker::end()).flowsTo(result)
}
/** Gets a reference to a header instance call/subscript */
private DataFlow::Node headerInstanceCall() {
headerInstance() in [result.(DataFlow::AttrRead), result.(DataFlow::AttrRead).getObject()] or
headerInstance().asExpr() = result.asExpr().(Subscript).getObject()
}
class FlaskHeaderDefinition extends DataFlow::Node, HeaderDeclaration::Range {
DataFlow::Node headerInput;
FlaskHeaderDefinition() {
this.asCfgNode().(DefinitionNode) = headerInstanceCall().asCfgNode() and
headerInput.asCfgNode() = this.asCfgNode().(DefinitionNode).getValue()
}
override DataFlow::Node getHeaderInput() {
result.asExpr() in [headerInput.asExpr(), this.asExpr().(Subscript).getIndex()]
}
}
private class FlaskMakeResponseExtend extends DataFlow::CallCfgNode, HeaderDeclaration::Range {
FlaskMakeResponseExtend() { this.getFunction() = headerInstanceCall() }
override DataFlow::Node getHeaderInput() { result = this.getArg(0) }
}
private class FlaskResponse extends DataFlow::CallCfgNode, HeaderDeclaration::Range {
FlaskResponse() { this = Flask::Response::classRef().getACall() }
override DataFlow::Node getHeaderInput() { result = this.getArgByName("headers") }
}
}

View File

@@ -0,0 +1,31 @@
/**
* Provides classes modeling security-relevant aspects of the `Werkzeug` PyPI package.
* See
* - https://pypi.org/project/Werkzeug/
* - https://werkzeug.palletsprojects.com/en/1.0.x/#werkzeug
*/
private import python
private import semmle.python.frameworks.Flask
private import semmle.python.dataflow.new.DataFlow
private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
private module Werkzeug {
module datastructures {
module Headers {
class WerkzeugHeaderAddCall extends DataFlow::CallCfgNode, HeaderDeclaration::Range {
WerkzeugHeaderAddCall() {
this.getFunction().(DataFlow::AttrRead).getObject().getALocalSource() =
API::moduleImport("werkzeug")
.getMember("datastructures")
.getMember("Headers")
.getACall() and
this.getFunction().(DataFlow::AttrRead).getAttributeName() = "add"
}
override DataFlow::Node getHeaderInput() { result = this.getArg(_) }
}
}
}
}