From dac71ded9d6ede982ed0fce88f0cb046f034ccd5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 20 Jul 2021 17:44:36 +0200 Subject: [PATCH] Python: Add Authorization modeling in Flask --- .../ql/src/semmle/python/frameworks/Flask.qll | 7 +++ .../src/semmle/python/frameworks/Werkzeug.qll | 44 +++++++++++++++++++ .../frameworks/flask/taint_test.py | 11 ++++- 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index cc214935e28..d53febcc91d 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -439,6 +439,13 @@ module Flask { } } + /** An `Authorization` instance that originates from a flask request. */ + private class FlaskRequestAuthorizationInstances extends Werkzeug::Authorization::InstanceSource { + FlaskRequestAuthorizationInstances() { + this.(DataFlow::AttrRead).accesses(request().getAUse(), "authorization") + } + } + // --------------------------------------------------------------------------- // Implicit response from returns of flask request handlers // --------------------------------------------------------------------------- diff --git a/python/ql/src/semmle/python/frameworks/Werkzeug.qll b/python/ql/src/semmle/python/frameworks/Werkzeug.qll index e82bfb846d5..c5f1c408f4d 100644 --- a/python/ql/src/semmle/python/frameworks/Werkzeug.qll +++ b/python/ql/src/semmle/python/frameworks/Werkzeug.qll @@ -169,6 +169,50 @@ module Werkzeug { } } + /** + * Provides models for the `werkzeug.datastructures.Authorization` class + * + * See https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Authorization. + */ + module Authorization { + /** + * A source of instances of `werkzeug.datastructures.Authorization`, 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 `Authorization::instance()` to get references to instances of `werkzeug.datastructures.Authorization`. + */ + abstract class InstanceSource extends DataFlow::LocalSourceNode { } + + /** Gets a reference to an instance of `werkzeug.datastructures.Authorization`. */ + private DataFlow::TypeTrackingNode 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 `werkzeug.datastructures.Authorization`. */ + DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } + + /** + * Taint propagation for `werkzeug.datastructures.Authorization`. + */ + class AuthorizationAdditionalTaintStep extends TaintTracking::AdditionalTaintStep { + override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + // Attributes + nodeFrom = instance() and + nodeTo.(DataFlow::AttrRead).getObject() = nodeFrom and + nodeTo.(DataFlow::AttrRead).getAttributeName() in [ + "username", "password", "realm", "nonce", "uri", "nc", "cnonce", "response", "opaque", + "qop" + ] + } + } + } + import WerkzeugOld } diff --git a/python/ql/test/library-tests/frameworks/flask/taint_test.py b/python/ql/test/library-tests/frameworks/flask/taint_test.py index c967cbb84e1..1c1f88eab68 100644 --- a/python/ql/test/library-tests/frameworks/flask/taint_test.py +++ b/python/ql/test/library-tests/frameworks/flask/taint_test.py @@ -44,7 +44,16 @@ def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler route # werkzeug.datastructures.Authorization (a dict, with some properties) request.authorization, # $ tainted request.authorization['username'], # $ tainted - request.authorization.username, # $ MISSING: tainted + request.authorization.username, # $ tainted + request.authorization.password, # $ tainted + request.authorization.realm, # $ tainted + request.authorization.nonce, # $ tainted + request.authorization.uri, # $ tainted + request.authorization.nc, # $ tainted + request.authorization.cnonce, # $ tainted + request.authorization.response, # $ tainted + request.authorization.opaque, # $ tainted + request.authorization.qop, # $ tainted # werkzeug.datastructures.RequestCacheControl request.cache_control, # $ tainted