mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Python: Add basic taint modeling of tornado request
This commit is contained in:
@@ -33,7 +33,7 @@ private module Tornado {
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node tornado_attr(DataFlow::TypeTracker t, string attr_name) {
|
||||
attr_name in ["web"] and
|
||||
attr_name in ["web", "httputil"] and
|
||||
(
|
||||
t.start() and
|
||||
result = DataFlow::importNode("tornado" + "." + attr_name)
|
||||
@@ -221,6 +221,148 @@ private module Tornado {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class RequestAttrAccess extends tornado::httputil::HttpServerRequest::InstanceSource {
|
||||
RequestAttrAccess() {
|
||||
this.(DataFlow::AttrRead).getObject() = instance() and
|
||||
this.(DataFlow::AttrRead).getAttributeName() = "request"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// tornado.httputil
|
||||
// -------------------------------------------------------------------------
|
||||
/** Gets a reference to the `tornado.httputil` module. */
|
||||
DataFlow::Node httputil() { result = tornado_attr("httputil") }
|
||||
|
||||
/** Provides models for the `tornado.httputil` module */
|
||||
module httputil {
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `tornado.httputil` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node httputil_attr(DataFlow::TypeTracker t, string attr_name) {
|
||||
attr_name in ["HTTPServerRequest"] and
|
||||
(
|
||||
t.start() and
|
||||
result = DataFlow::importNode("tornado.httputil" + "." + attr_name)
|
||||
or
|
||||
t.startInAttr(attr_name) and
|
||||
result = httputil()
|
||||
)
|
||||
or
|
||||
// Due to bad performance when using normal setup with `httputil_attr(t2, attr_name).track(t2, t)`
|
||||
// we have inlined that code and forced a join
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
exists(DataFlow::StepSummary summary |
|
||||
httputil_attr_first_join(t2, attr_name, result, summary) and
|
||||
t = t2.append(summary)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate httputil_attr_first_join(
|
||||
DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,
|
||||
DataFlow::StepSummary summary
|
||||
) {
|
||||
DataFlow::StepSummary::step(httputil_attr(t2, attr_name), res, summary)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the attribute `attr_name` of the `tornado.httputil` module.
|
||||
* WARNING: Only holds for a few predefined attributes.
|
||||
*/
|
||||
private DataFlow::Node httputil_attr(string attr_name) {
|
||||
result = httputil_attr(DataFlow::TypeTracker::end(), attr_name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides models for the `tornado.httputil.HttpServerRequest` class
|
||||
*
|
||||
* See https://www.tornadoweb.org/en/stable/httputil.html#tornado.httputil.HTTPServerRequest.
|
||||
*/
|
||||
module HttpServerRequest {
|
||||
/** Gets a reference to the `tornado.httputil.HttpServerRequest` class. */
|
||||
private DataFlow::Node classRef(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = httputil_attr("HttpServerRequest")
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = classRef(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to the `tornado.httputil.HttpServerRequest` class. */
|
||||
DataFlow::Node classRef() { result = classRef(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/**
|
||||
* A source of instances of `tornado.httputil.HttpServerRequest`, extend this class to model new instances.
|
||||
*
|
||||
* This can include instantiations of the class, return values from function
|
||||
* calls, or a special parameter that will be set when functions are called by an external
|
||||
* library.
|
||||
*
|
||||
* Use the predicate `HttpServerRequest::instance()` to get references to instances of `tornado.httputil.HttpServerRequest`.
|
||||
*/
|
||||
abstract class InstanceSource extends DataFlow::Node { }
|
||||
|
||||
/** A direct instantiation of `tornado.httputil.HttpServerRequest`. */
|
||||
private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode {
|
||||
override CallNode node;
|
||||
|
||||
ClassInstantiation() { node.getFunction() = classRef().asCfgNode() }
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `tornado.httputil.HttpServerRequest`. */
|
||||
private DataFlow::Node instance(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result instanceof InstanceSource
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `tornado.httputil.HttpServerRequest`. */
|
||||
DataFlow::Node instance() { result = instance(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/** Gets a reference to the `full_url` method. */
|
||||
private DataFlow::Node full_url(DataFlow::TypeTracker t) {
|
||||
t.startInAttr("full_url") and
|
||||
result = instance()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = full_url(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to the `full_url` method. */
|
||||
DataFlow::Node full_url() { result = full_url(DataFlow::TypeTracker::end()) }
|
||||
|
||||
private class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// Method access
|
||||
nodeTo.(DataFlow::AttrRead).getObject() = nodeFrom and
|
||||
nodeFrom = instance() and
|
||||
nodeTo in [full_url()]
|
||||
or
|
||||
// Method call
|
||||
nodeTo.asCfgNode().(CallNode).getFunction() = nodeFrom.asCfgNode() and
|
||||
nodeFrom in [full_url()]
|
||||
or
|
||||
// Attributes
|
||||
nodeFrom = instance() and
|
||||
exists(DataFlow::AttrRead read | nodeTo = read and read.getObject() = nodeFrom |
|
||||
read.getAttributeName() in [
|
||||
// str / bytes
|
||||
"uri", "path", "query", "remote_ip", "body",
|
||||
// Dict[str, List[bytes]]
|
||||
"arguments", "query_arguments", "body_arguments",
|
||||
// dict-like, https://www.tornadoweb.org/en/stable/httputil.html#tornado.httputil.HTTPHeaders
|
||||
"headers",
|
||||
// Dict[str, http.cookies.Morsel]
|
||||
"cookies"
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,27 +15,27 @@
|
||||
| taint_test.py:26 | ok | get | self.path_kwargs |
|
||||
| taint_test.py:27 | ok | get | self.path_kwargs["name"] |
|
||||
| taint_test.py:34 | ok | get | request |
|
||||
| taint_test.py:36 | fail | get | request.uri |
|
||||
| taint_test.py:37 | fail | get | request.path |
|
||||
| taint_test.py:38 | fail | get | request.query |
|
||||
| taint_test.py:39 | fail | get | request.full_url() |
|
||||
| taint_test.py:41 | fail | get | request.remote_ip |
|
||||
| taint_test.py:43 | fail | get | request.body |
|
||||
| taint_test.py:45 | fail | get | request.arguments |
|
||||
| taint_test.py:46 | fail | get | request.arguments["name"] |
|
||||
| taint_test.py:47 | fail | get | request.arguments["name"][0] |
|
||||
| taint_test.py:49 | fail | get | request.query_arguments |
|
||||
| taint_test.py:50 | fail | get | request.query_arguments["name"] |
|
||||
| taint_test.py:51 | fail | get | request.query_arguments["name"][0] |
|
||||
| taint_test.py:53 | fail | get | request.body_arguments |
|
||||
| taint_test.py:54 | fail | get | request.body_arguments["name"] |
|
||||
| taint_test.py:55 | fail | get | request.body_arguments["name"][0] |
|
||||
| taint_test.py:58 | fail | get | request.headers |
|
||||
| taint_test.py:59 | fail | get | request.headers["header-name"] |
|
||||
| taint_test.py:36 | ok | get | request.uri |
|
||||
| taint_test.py:37 | ok | get | request.path |
|
||||
| taint_test.py:38 | ok | get | request.query |
|
||||
| taint_test.py:39 | ok | get | request.full_url() |
|
||||
| taint_test.py:41 | ok | get | request.remote_ip |
|
||||
| taint_test.py:43 | ok | get | request.body |
|
||||
| taint_test.py:45 | ok | get | request.arguments |
|
||||
| taint_test.py:46 | ok | get | request.arguments["name"] |
|
||||
| taint_test.py:47 | ok | get | request.arguments["name"][0] |
|
||||
| taint_test.py:49 | ok | get | request.query_arguments |
|
||||
| taint_test.py:50 | ok | get | request.query_arguments["name"] |
|
||||
| taint_test.py:51 | ok | get | request.query_arguments["name"][0] |
|
||||
| taint_test.py:53 | ok | get | request.body_arguments |
|
||||
| taint_test.py:54 | ok | get | request.body_arguments["name"] |
|
||||
| taint_test.py:55 | ok | get | request.body_arguments["name"][0] |
|
||||
| taint_test.py:58 | ok | get | request.headers |
|
||||
| taint_test.py:59 | ok | get | request.headers["header-name"] |
|
||||
| taint_test.py:60 | fail | get | request.headers.get_list(..) |
|
||||
| taint_test.py:61 | fail | get | request.headers.get_all() |
|
||||
| taint_test.py:62 | fail | get | ListComp |
|
||||
| taint_test.py:65 | fail | get | request.cookies |
|
||||
| taint_test.py:66 | fail | get | request.cookies["cookie-name"] |
|
||||
| taint_test.py:65 | ok | get | request.cookies |
|
||||
| taint_test.py:66 | ok | get | request.cookies["cookie-name"] |
|
||||
| taint_test.py:67 | fail | get | request.cookies["cookie-name"].key |
|
||||
| taint_test.py:68 | fail | get | request.cookies["cookie-name"].value |
|
||||
|
||||
Reference in New Issue
Block a user