From edae9d5f07c7e6420d71a385a5927eda0d66856c Mon Sep 17 00:00:00 2001 From: Aditya Sharad Date: Tue, 8 Nov 2022 16:45:19 -0800 Subject: [PATCH 1/7] Universe 2022: Limit to handler methods within ActionController classes --- workshop-2022/README.md | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/workshop-2022/README.md b/workshop-2022/README.md index c310f46..d6dc482 100644 --- a/workshop-2022/README.md +++ b/workshop-2022/README.md @@ -281,7 +281,35 @@ The arguments of these method calls are the URLs being redirected to, and hence ``` -1. The previous step may now find too many possible methods! Methods named `create/update/destroy/delete` are probably not HTTP `GET` handlers if we can't find a `GET` route in the code. Exclude them from your class. +1. The previous step may now find too many possible methods! Limit your class to methods declared within `ActionController` classes. + +
+ Hint + + - Use the `exists` or `any` quantifiers to declare a variable of type `ActionControllerControllerClass`, and assert that `this` is one of the methods of such a class. + - Use Quick Evaluation on the characteristic predicate to see all values of your new class. + - Use the Compare Results command in the Query History view to view the differences in results. + +
+
+ Solution + + ```ql + import codeql.ruby.AST + import codeql.ruby.frameworks.ActionController + + class GetHandlerMethod extends MethodBase { + GetHandlerMethod() { + this.(ActionControllerActionMethod).getARoute().getHttpMethod() = "get" + or + not exists(this.(ActionControllerActionMethod).getARoute()) and + this = any(ActionControllerControllerClass c).getAMethod() + } + } + ``` +
+ +1. The previous step may still find too many possible methods! Methods named `create/update/destroy/delete` are probably not HTTP `GET` handlers if we can't find a `GET` route in the code. Exclude them from your class.
Hint @@ -304,6 +332,7 @@ The arguments of these method calls are the URLs being redirected to, and hence this.(ActionControllerActionMethod).getARoute().getHttpMethod() = "get" or not exists(this.(ActionControllerActionMethod).getARoute()) and + this = any(ActionControllerControllerClass c).getAMethod() and not this.getName().regexpMatch(".*(create|update|destroy).*") } } @@ -332,6 +361,7 @@ The arguments of these method calls are the URLs being redirected to, and hence this.(ActionControllerActionMethod).getARoute().getHttpMethod() = "get" or not exists(this.(ActionControllerActionMethod).getARoute()) and + this = any(ActionControllerControllerClass c).getAMethod() and not this.getName().regexpMatch(".*(create|update|destroy).*") } } @@ -577,6 +607,7 @@ select sink, "Potential URL redirection" this.(ActionControllerActionMethod).getARoute().getHttpMethod() = "get" or not exists(this.(ActionControllerActionMethod).getARoute()) and + this = any(ActionControllerControllerClass c).getAMethod() and not this.getName().regexpMatch(".*(create|update|destroy).*") } } @@ -584,7 +615,7 @@ select sink, "Potential URL redirection" predicate isRedirect(DataFlow::Node redirectLocation, GetHandlerMethod method) { exists(Http::Server::HttpRedirectResponse redirectCall | redirectCall.getRedirectLocation() = redirectLocation and - redirectCall.asExpr().asExpr().getEnclosingMethod() = method + redirectCall.asExpr().getExpr().getEnclosingMethod() = method ) } From 3cdf9bea8eec9e6806ba280b4bc9b5cd0cbfdc6e Mon Sep 17 00:00:00 2001 From: Aditya Sharad Date: Tue, 8 Nov 2022 16:56:32 -0800 Subject: [PATCH 2/7] Universe 2022: Rewrite library imports and type references Use the default `import ruby` instead of having to specifically import the `codeql.ruby.AST` and `codeql.ruby.DataFlow` libraries. Both libraries are imported by default in `ruby.qll`. This makes imports simpler, but means we have to qualify all uses of AST node types with `Ast::`. We already had to qualify uses of data flow node types with `DataFlow::`. --- workshop-2022/README.md | 97 +++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/workshop-2022/README.md b/workshop-2022/README.md index d6dc482..7422a19 100644 --- a/workshop-2022/README.md +++ b/workshop-2022/README.md @@ -80,20 +80,21 @@ We will use this reasoning to identify specific Ruby on Rails method calls, whic The arguments of these method calls are the URLs being redirected to, and hence are potential **sinks** for URL redirection vulnerabilities. -1. Find all method calls in the program. To reason about the abstract syntax tree (AST) of a Ruby program, starting by adding `import codeql.ruby.AST` to your CodeQL query. +1. Find all method calls in the program. To reason about the abstract syntax tree (AST) of a Ruby program, start by adding `import ruby` to your CodeQL query, and use the types defined in the `Ast` module.
Hint - - A method call is represented by the `MethodCall` type in the CodeQL Ruby library. + - Start typing `from Ast::` to see the types available in the AST library. + - A method call is represented by the `Ast::MethodCall` type in the CodeQL Ruby library.
Solution ```ql - import codeql.ruby.AST + import ruby - from MethodCall call + from Ast::MethodCall call select call ```
@@ -113,9 +114,9 @@ The arguments of these method calls are the URLs being redirected to, and hence Solution ```ql - import codeql.ruby.AST + import ruby - from MethodCall redirectCall + from Ast::MethodCall redirectCall where redirectCall.getMethodName() = "redirect_to" select redirectCall @@ -129,7 +130,7 @@ The arguments of these method calls are the URLs being redirected to, and hence - `MethodCall.getAnArgument()` returns all possible arguments of the method call. - `MethodCall.getArgument(int i)` returns the argument at (0-based) index `i` of the method call. - - The argument is an _expression_ in the program, represented by the CodeQL class `Expr`. + - The argument is an _expression_ in the program, represented by the CodeQL class `Ast::Expr`. - Introduce a new variable in the `from` clause to hold this expression, and output the variable in the `select` clause.
@@ -137,9 +138,9 @@ The arguments of these method calls are the URLs being redirected to, and hence Solution ```ql - import codeql.ruby.AST + import ruby - from MethodCall redirectCall, Expr arg + from Ast::MethodCall redirectCall, Ast::Expr arg where redirectCall.getMethodName() = "redirect_to" and arg = redirectCall.getArgument(0) @@ -149,8 +150,8 @@ The arguments of these method calls are the URLs being redirected to, and hence 1. Recall that _predicates_ allow you to encapsulate logical conditions in a reusable format. Convert your previous query to a predicate which identifies the set of expressions in the program which are arguments of `redirect_to` method calls. You can use the following template: ```ql - predicate isRedirect(Expr redirectLocation) { - exists(MethodCall redirectCall | + predicate isRedirect(Ast::Expr redirectLocation) { + exists(Ast::MethodCall redirectCall | // TODO fill me in ) } @@ -169,10 +170,10 @@ The arguments of these method calls are the URLs being redirected to, and hence Solution ```ql - import codeql.ruby.AST + import ruby - predicate isRedirect(Expr redirectLocation) { - exists(MethodCall redirectCall | + predicate isRedirect(Ast::Expr redirectLocation) { + exists(Ast::MethodCall redirectCall | redirectCall.getMethodName() = "redirect_to" and redirectLocation = redirectCall.getArgument(0) ) @@ -185,16 +186,16 @@ The arguments of these method calls are the URLs being redirected to, and hence Solution ```ql - import codeql.ruby.AST + import ruby - predicate isRedirect(Expr redirectLocation) { - exists(MethodCall redirectCall | + predicate isRedirect(Ast::Expr redirectLocation) { + exists(Ast::MethodCall redirectCall | redirectCall.getMethodName() = "redirect_to" and redirectLocation = redirectCall.getArgument(0) ) } - from Expr e + from Ast::Expr e where isRedirect(e) select e ``` @@ -202,7 +203,7 @@ The arguments of these method calls are the URLs being redirected to, and hence 1. Like predicates, _classes_ in CodeQL can be used to encapsulate reusable portions of logic. Classes represent sets of values, and they can also include operations (known as _member predicates_) specific to that set of values. You have already seen some CodeQL classes (`MethodCall`, `Expr` etc.) and associated member predicates (`MethodCall.getMethodName()`, `MethodCall.getArgument(int i)`, etc.). - `MethodBase` is the class of all Ruby methods. Create a subclass named `GetHandlerMethod`. To begin with, your subclass will contain all the values from the superclass. + `Ast::MethodBase` is the class of all Ruby methods. Create a subclass named `GetHandlerMethod`. To begin with, your subclass will contain all the values from the superclass.
Hint @@ -213,9 +214,9 @@ The arguments of these method calls are the URLs being redirected to, and hence Solution ```ql - import codeql.ruby.AST + import ruby - class GetHandlerMethod extends MethodBase {} + class GetHandlerMethod extends Ast::MethodBase {} ```
@@ -240,10 +241,10 @@ The arguments of these method calls are the URLs being redirected to, and hence Solution ```ql - import codeql.ruby.AST + import ruby import codeql.ruby.frameworks.ActionController - class GetHandlerMethod extends MethodBase { + class GetHandlerMethod extends Ast::MethodBase { GetHandlerMethod() { this.(ActionControllerActionMethod).getARoute().getHttpMethod() = "get" } @@ -268,10 +269,10 @@ The arguments of these method calls are the URLs being redirected to, and hence Solution ```ql - import codeql.ruby.AST + import ruby import codeql.ruby.frameworks.ActionController - class GetHandlerMethod extends MethodBase { + class GetHandlerMethod extends Ast::MethodBase { GetHandlerMethod() { this.(ActionControllerActionMethod).getARoute().getHttpMethod() = "get" or @@ -295,10 +296,10 @@ The arguments of these method calls are the URLs being redirected to, and hence Solution ```ql - import codeql.ruby.AST + import ruby import codeql.ruby.frameworks.ActionController - class GetHandlerMethod extends MethodBase { + class GetHandlerMethod extends Ast::MethodBase { GetHandlerMethod() { this.(ActionControllerActionMethod).getARoute().getHttpMethod() = "get" or @@ -324,10 +325,10 @@ The arguments of these method calls are the URLs being redirected to, and hence Solution ```ql - import codeql.ruby.AST + import ruby import codeql.ruby.frameworks.ActionController - class GetHandlerMethod extends MethodBase { + class GetHandlerMethod extends Ast::MethodBase { GetHandlerMethod() { this.(ActionControllerActionMethod).getARoute().getHttpMethod() = "get" or @@ -353,10 +354,10 @@ The arguments of these method calls are the URLs being redirected to, and hence Solution ```ql - import codeql.ruby.AST + import ruby import codeql.ruby.frameworks.ActionController - class GetHandlerMethod extends MethodBase { + class GetHandlerMethod extends Ast::MethodBase { GetHandlerMethod() { this.(ActionControllerActionMethod).getARoute().getHttpMethod() = "get" or @@ -366,8 +367,8 @@ The arguments of these method calls are the URLs being redirected to, and hence } } - predicate isRedirect(Expr redirectLocation, GetHandlerMethod method) { - exists(MethodCall redirectCall | + predicate isRedirect(Ast::Expr redirectLocation, GetHandlerMethod method) { + exists(Ast::MethodCall redirectCall | redirectCall.getMethodName() = "redirect_to" and redirectLocation = redirectCall.getArgument(0) and redirectCall.getEnclosingMethod() = method @@ -382,26 +383,24 @@ The arguments of these method calls are the URLs being redirected to, and hence In this section, we will move from reasoning about the AST to reasoning about data flow. The data flow graph is built on top of the AST, but contains more detailed semantic information about the flow of information through the program. We will also use more concepts that are already modelled in the CodeQL standard libraries for Ruby, instead of having to manually model each pattern. -1. The `DataFlow` library models the flow of data through the program. Import this library using `import codeql.ruby.DataFlow`. The class `DataFlow::Node` from this library represents semantic elements in the program that may have a value. Data flow nodes typically have corresponding AST nodes, but we can perform more sophisticated reasoning on the data flow graph. Modify your predicate from the previous section to reason about data flow nodes instead of AST nodes. +1. The `DataFlow` library models the flow of data through the program. This is already imported by `import ruby`, but you can also explicitly import it using `import codeql.ruby.DataFlow`. The class `DataFlow::Node` from this library represents semantic elements in the program that may have a value. Data flow nodes typically have corresponding AST nodes, but we can perform more sophisticated reasoning on the data flow graph. Modify your predicate from the previous section to reason about data flow nodes instead of AST nodes.
Hint - - Add `import codeql.ruby.DataFlow`. - - Change the type of `redirectLocation` from `Expr` to `DataFlow::Node`. This is the generic type of all data flow nodes. Most nodes correspond to expressions or parameters in the AST. - - Change the type of `redirectCall` from `MethodCall` to `DataFlow::CallNode`. This is a more specialised type of data flow node, corresponding to a particular type of expression in the AST -- a `Call`. + - Change the type of `redirectLocation` from `Ast::Expr` to `DataFlow::Node`. This is the generic type of all data flow nodes. Most nodes correspond to expressions or parameters in the AST. + - Change the type of `redirectCall` from `Ast::MethodCall` to `DataFlow::CallNode`. This is a more specialised type of data flow node, corresponding to a particular type of expression in the AST -- a `Call`. - There are still compilation errors! Methods are a concept in the AST, not the data flow graph. We cannot call `getEnclosingMethod` on a `DataFlow::Node`, so we have to convert it first into an AST node. - - Use `asExpr()` to convert from a `DataFlow::Node` into an `ExprCfgNode` -- this is a type of node in the "control flow" graph. - - Use `getExpr()` to convert from a `ExprCfgNode` into an `Expr` -- this is a type of AST node. + - Use `asExpr()` to convert from a `DataFlow::Node` into a `Cfg::ExprCfgNode` -- this is a type of node in the "control flow" graph. + - Use `getExpr()` to convert from a `ExprCfgNode` into an `Ast::Expr` -- this is a type of AST node. - The rest of the predicate continues to compile without errors. This is because structural predicates like `getArgument` are defined in parallel on both the AST library and the data flow library.
Solution ```ql - import codeql.ruby.AST + import ruby import codeql.ruby.frameworks.ActionController - import codeql.ruby.DataFlow predicate isRedirect(DataFlow::Node redirectLocation, GetHandlerMethod method) { exists(DataFlow::CallNode redirectCall | @@ -427,9 +426,8 @@ The data flow graph is built on top of the AST, but contains more detailed seman Solution ```ql - import codeql.ruby.AST + import ruby import codeql.ruby.frameworks.ActionController - import codeql.ruby.DataFlow import codeql.ruby.Concepts predicate isRedirect(DataFlow::Node redirectLocation, GetHandlerMethod method) { @@ -473,11 +471,11 @@ In program analysis we call this a _data flow_ or _taint tracking_ problem. Data We can visualize the data flow problem as one of finding paths through a directed graph, where the nodes of the graph are elements in the program that have a value, and the edges represent the flow of data between those elements. If a path exists, then the data flows between those two nodes. -CodeQL for Ruby provides data flow analysis as part of the standard library. You can import it using `import codeql.ruby.DataFlow` and `codeql.ruby.TaintTracking`. The library models nodes using the `DataFlow::Node` CodeQL class. These nodes are separate and distinct from the AST (Abstract Syntax Tree, which represents the basic structure of the program) nodes, to allow for flexibility in how data flow is modeled. +CodeQL for Ruby provides data flow analysis as part of the standard library. You can import the data flow library using `import ruby` (which in turn imports `codeql.ruby.DataFlow`), and you can import the taint tracking library using `import codeql.ruby.TaintTracking`. Data flow tracks the flow of the same precise values through the program. Taint tracking is less precise, and tracks the flow of values that may change slightly through the program. Both libraries model program elements using the `DataFlow::Node` CodeQL class. These nodes are separate and distinct from the AST (Abstract Syntax Tree) nodes, which represent the basic structure of the program. This allows greater flexibility in how data flow is modeled. There are a small number of data flow node types – expression nodes and parameter nodes are most common. We have seen the `asExpr()` method to convert a `DataFlow::Node` into the corresponding control flow node and the `getExpr()` method to convert a control flow node into the corresponding AST node; there is also `asParameter()`. -In this section we will create a data flow query by populating this template: +In this section we will create a taint tracking query by populating this template: ```ql /** @@ -485,10 +483,9 @@ In this section we will create a data flow query by populating this template: * @kind problem * @id rb/url-redirection */ -import codeql.ruby.AST +import ruby import codeql.ruby.frameworks.ActionController import codeql.ruby.Concepts -import codeql.ruby.DataFlow import codeql.ruby.dataflow.RemoteFlowSources import codeql.ruby.TaintTracking @@ -550,10 +547,9 @@ select sink, "Potential URL redirection" * @kind problem * @id rb/url-redirection */ - import codeql.ruby.AST + import ruby import codeql.ruby.frameworks.ActionController import codeql.ruby.Concepts - import codeql.ruby.DataFlow import codeql.ruby.dataflow.RemoteFlowSources import codeql.ruby.TaintTracking @@ -594,10 +590,9 @@ select sink, "Potential URL redirection" * @kind path-problem * @id rb/url-redirection */ - import codeql.ruby.AST + import ruby import codeql.ruby.frameworks.ActionController import codeql.ruby.Concepts - import codeql.ruby.DataFlow import codeql.ruby.dataflow.RemoteFlowSources import codeql.ruby.TaintTracking import DataFlow::PathGraph From 9fc437edbfdaac09aca809853859934b85426a56 Mon Sep 17 00:00:00 2001 From: Aditya Sharad Date: Tue, 8 Nov 2022 23:25:14 -0800 Subject: [PATCH 3/7] Universe 2022: Minor readme improvements --- workshop-2022/README.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/workshop-2022/README.md b/workshop-2022/README.md index 7422a19..e5c30a3 100644 --- a/workshop-2022/README.md +++ b/workshop-2022/README.md @@ -13,10 +13,13 @@ Closer to the workshop date, the detailed workshop steps will be available below - [On Codespaces](#setup-codespaces) - Useful commands - [Workshop](#workshop) + - [Section 1: syntactic reasoning](#section1) + - [Section 2: semantic reasoning](#section2) + - [Section 3: URL redirection](#section3) ## Prerequisites and setup instructions -### On your local machine) +### On your local machine Please complete this section before the workshop, if possible. @@ -65,7 +68,11 @@ Coming soon! ### Problem statement -In this workshop we will look for _URL redirection vulnerabilities_ in Ruby code using the Ruby on Rails framework. The example that we will find was a potential vulnerability in the open-source project management software OpenProject, which was introduced in a pull request, identified by CodeQL static analysis on the PR, diagnosed during PR review, and fixed before the PR was merged. It remained a potential problem, not a real vulnerability, thanks to the efforts of the project maintainers. However, it is a good example to help us understand and detect serious URL redirection vulnerabilities that may occur elsewhere. +In this workshop we will look for _URL redirection vulnerabilities_ in Ruby code that uses the Ruby on Rails framework. Such vulnerabilities can occur in web applications when a URL string that is controlled by an external user makes its way to application code that redirects the current user's browser to the supplied URL. + +The example that we will find was a potential vulnerability in the open-source project management software [OpenProject](https://github.com/opf/openproject), which was introduced in a pull request, identified by CodeQL static analysis on the PR, diagnosed during PR review, and fixed before the PR was merged. Note that it remained a potential problem, not a real vulnerability, thanks to the efforts of the project maintainers and a safe default setting built into Rails 7. However, it is a good example to help us understand and detect serious URL redirection vulnerabilities that may occur elsewhere. + +(OpenProject is licensed under the [GNU GPL v3.0](https://github.com/opf/openproject/blob/dev/LICENSE).) The workshop is split into several steps. You can write one query per step, or work with a single query that you refine at each step. Each step has a **hint** that describes useful classes and predicates in the CodeQL standard libraries for Ruby. @@ -439,7 +446,11 @@ The data flow graph is built on top of the AST, but contains more detailed seman ```
-1. Define a new predicate `isSource(DataFlow::Node source)` that describes **sources** of untrusted user input in the program. The CodeQL standard libraries have a class that already models this for you. +1. [`params`](https://api.rubyonrails.org/v7.0.4/classes/ActionController/StrongParameters.html#method-i-params) is a method available on Rails controller classes. It returns a hash (specifically of type [`ActionController::Parameters`](https://guides.rubyonrails.org/action_controller_overview.html#parameters)) that has been instantiated (by Rails) with the parameters of the incoming HTTP request. + + These parameters are a source of remote user input. In the CodeQL standard library for Ruby, they are modelled by the `ParamsSource` class, which is a subclass of the more general `RemoteFlowSource` class. + + Define a new predicate `isSource(DataFlow::Node source)` that describes all **sources** of remote user input in the program.
Hint @@ -631,7 +642,7 @@ select sink, "Potential URL redirection" ```
-For more information on how this potential vulnerability was identified early and fixed, please read [the discussion in this pull request](https://github.com/opf/openproject/pull/10708#discussion_r892299693). This potential problem never made it into the development branch or production code, thanks to the efforts of the project maintainers. However, it is a good example to help us understand and detect URL redirection vulnerabilities that may occur elsewhere. +For more information on how this potential vulnerability was identified early and fixed, please read [the discussion in this pull request](https://github.com/opf/openproject/pull/10708#discussion_r892299693). This potential problem never made it into the development branch or production code, thanks to the efforts of the project maintainers, and the codebase was also safe due to the use of Rails 7, which blocks open redirects by default. However, it is a good example to help us understand and detect more serious URL redirection vulnerabilities that may occur elsewhere. ## What's next? - [CodeQL overview](https://codeql.github.com/docs/codeql-overview/) From 29de5b38d5b366a24afd25a818f14521fd006a5e Mon Sep 17 00:00:00 2001 From: Aditya Sharad Date: Tue, 8 Nov 2022 23:30:54 -0800 Subject: [PATCH 4/7] Universe 2022: Add Codespaces configuration and instructions --- .devcontainer/devcontainer.json | 14 ++++++++++++++ workshop-2022/README.md | 10 +++++++++- workshop-2022/workshop.code-workspace | 7 +++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/devcontainer.json create mode 100644 workshop-2022/workshop.code-workspace diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..5725e28 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,14 @@ +{ + "extensions": [ + "github.vscode-codeql", + "vsls-contrib.codetour" + ], + "customizations": { + "codespaces": { + "openFiles": [ + "workshop-2022/README.md", + "workshop-2022/workshop.code-workspace" + ] + } + } +} \ No newline at end of file diff --git a/workshop-2022/README.md b/workshop-2022/README.md index e5c30a3..389b3ea 100644 --- a/workshop-2022/README.md +++ b/workshop-2022/README.md @@ -23,6 +23,7 @@ Closer to the workshop date, the detailed workshop steps will be available below Please complete this section before the workshop, if possible. +#### Installation - Install [Visual Studio Code](https://code.visualstudio.com/). - Install the [CodeQL extension for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/setting-up-codeql-in-visual-studio-code/). - You do _not_ need to install the CodeQL CLI: the extension will handle this for you. @@ -32,6 +33,9 @@ Please complete this section before the workshop, if possible. ``` - Use `git pull origin main` to regularly keep this clone up to date with the latest state of the repository. - Open the repository in Visual Studio Code: **File** > **Open** (or **Open Folder**) > Browse to the checkout of `githubuniverseworkshops/codeql`. +- Follow **Common setup steps (local and Codespaces)** below. + +#### Common setup steps (local and Codespaces) - Import the [CodeQL database](https://github.com/githubuniverseworkshops/codeql/releases/download/universe-2022/codeql-ruby-workshop-opf-openproject.zip) to be used in the workshop: - Click the **CodeQL** rectangular icon in the left sidebar. - Place your mouse over **Databases**, and click the cloud-shaped icon labelled `Download Database`. @@ -51,7 +55,11 @@ Please complete this section before the workshop, if possible. ### On Codespaces -Coming soon! +- Go to https://github.com/githubuniverseworkshops/codeql/codespaces. +- Click **Create codespace on main**. +- A Codespace will open in a new browser tab. +- When the Codespace is ready, it will open a VS Code workspace file, and prompt you to open this workspace and reload. Accept the prompt. The Codespace will reload. +- After the Codespace reloads, follow **Common setup steps (local and Codespaces)** under [On your local machine](#setup). ### Useful commands - Run a query using the following commands from the Command Palette (`Cmd/Ctrl + Shift + P`) or right-click menu: diff --git a/workshop-2022/workshop.code-workspace b/workshop-2022/workshop.code-workspace new file mode 100644 index 0000000..165d1d5 --- /dev/null +++ b/workshop-2022/workshop.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "." + }, + ] +} \ No newline at end of file From d4a6f734305731cfd7bb97d9585d46a14846727b Mon Sep 17 00:00:00 2001 From: Aditya Sharad Date: Tue, 8 Nov 2022 23:41:34 -0800 Subject: [PATCH 5/7] Universe 2022: Move workspace file to the root Codespaces will detect this file and prompt the user to open this workspace. --- .../workshop.code-workspace => workshop-2022.code-workspace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename workshop-2022/workshop.code-workspace => workshop-2022.code-workspace (51%) diff --git a/workshop-2022/workshop.code-workspace b/workshop-2022.code-workspace similarity index 51% rename from workshop-2022/workshop.code-workspace rename to workshop-2022.code-workspace index 165d1d5..b0c7d4f 100644 --- a/workshop-2022/workshop.code-workspace +++ b/workshop-2022.code-workspace @@ -1,7 +1,7 @@ { "folders": [ { - "path": "." + "path": "workshop-2022" }, ] } \ No newline at end of file From 455316d9034ddf18799440c59530f9f8fdf030cb Mon Sep 17 00:00:00 2001 From: Aditya Sharad Date: Tue, 8 Nov 2022 23:50:52 -0800 Subject: [PATCH 6/7] Universe 2022: Update Codespaces config and general setup instructions --- .devcontainer/devcontainer.json | 4 ++-- workshop-2022/README.md | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 5725e28..6d51a18 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,8 +6,8 @@ "customizations": { "codespaces": { "openFiles": [ - "workshop-2022/README.md", - "workshop-2022/workshop.code-workspace" + "workshop-2022.code-workspace", + "workshop-2022/README.md" ] } } diff --git a/workshop-2022/README.md b/workshop-2022/README.md index 389b3ea..6eb5337 100644 --- a/workshop-2022/README.md +++ b/workshop-2022/README.md @@ -38,10 +38,12 @@ Please complete this section before the workshop, if possible. #### Common setup steps (local and Codespaces) - Import the [CodeQL database](https://github.com/githubuniverseworkshops/codeql/releases/download/universe-2022/codeql-ruby-workshop-opf-openproject.zip) to be used in the workshop: - Click the **CodeQL** rectangular icon in the left sidebar. - - Place your mouse over **Databases**, and click the cloud-shaped icon labelled `Download Database`. + - The first time you do this, the CodeQL extension will download the CodeQL CLI. + - In the **Databases** panel, place your mouse over the title, and click the cloud-shaped icon labelled `Download Database` OR click the button **From a URL (as a zip file)**. - Copy and paste this URL into the box, then press **OK**/**Enter**: https://github.com/githubuniverseworkshops/codeql/releases/download/universe-2022/codeql-ruby-workshop-opf-openproject.zip - - The CodeQL extension will download the CodeQL CLI and the chosen database. - - After the database is downloaded, it will appear in the left sidebar under **Databases**. Click on the database name, and click **Set Current Database**. + - The CodeQL extension will download the chosen database. + - After the database is downloaded, it will appear in the left sidebar under **Databases**. Look for a checkmark to the left of the database name, indicating it is selected. + - If the database is not selected, hover your cursor on the database name, and click **Set Current Database**. - Install the CodeQL library package for analyzing Ruby code. - From the Command Palette (`Cmd/Ctrl+Shift+P`), search for and run the command `CodeQL: Install Pack Dependencies`. - At the top of your VS Code window, type `github` in the box to filter the list. @@ -58,7 +60,8 @@ Please complete this section before the workshop, if possible. - Go to https://github.com/githubuniverseworkshops/codeql/codespaces. - Click **Create codespace on main**. - A Codespace will open in a new browser tab. -- When the Codespace is ready, it will open a VS Code workspace file, and prompt you to open this workspace and reload. Accept the prompt. The Codespace will reload. +- When the Codespace is ready, it will open a VS Code workspace file `workshop-2022.code-workspace`. +- Click **Open Workspace** in the bottom right. The Codespace will reload. - After the Codespace reloads, follow **Common setup steps (local and Codespaces)** under [On your local machine](#setup). ### Useful commands From 8dcf83e3f9dcc31457632c51b021e9c192466ce2 Mon Sep 17 00:00:00 2001 From: Aditya Sharad Date: Mon, 14 Nov 2022 15:22:03 -0800 Subject: [PATCH 7/7] Universe 2022: Add solution --- workshop-2022/solution.ql | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 workshop-2022/solution.ql diff --git a/workshop-2022/solution.ql b/workshop-2022/solution.ql new file mode 100644 index 0000000..ec98e7b --- /dev/null +++ b/workshop-2022/solution.ql @@ -0,0 +1,53 @@ +/** + * @name URL redirection + * @kind path-problem + * @id rb/workshop/url-redirection + */ +import ruby +import codeql.ruby.frameworks.ActionController +import codeql.ruby.Concepts +import codeql.ruby.dataflow.RemoteFlowSources +import codeql.ruby.TaintTracking +import DataFlow::PathGraph + +/** + * Holds if `redirectLocation` is the target of a URL redirect call + * within a Rails application and `method` is the HTTP request handler + * method enclosing the call. + */ +predicate isRedirect(DataFlow::Node redirectLocation, GetHandlerMethod method) { + exists(Http::Server::HttpRedirectResponse redirectCall | + redirectCall.getRedirectLocation() = redirectLocation and + redirectCall.asExpr().getExpr().getEnclosingMethod() = method + ) +} + +/** + * A method in a Rails `ActionController` subclass that is likely + * to be the target of a route handler for an HTTP `GET` request. + */ +class GetHandlerMethod extends Ast::MethodBase { + GetHandlerMethod() { + this.(ActionControllerActionMethod).getARoute().getHttpMethod() = "get" + or + not exists(this.(ActionControllerActionMethod).getARoute()) and + exists(ActionControllerControllerClass c | this = c.getAMethod()) and + not this.getName().regexpMatch(".*(create|update|destroy|delete).*") + } +} + +class UrlRedirectionConfig extends TaintTracking::Configuration { + UrlRedirectionConfig() { this = "UrlRedirectionConfig" } + + override predicate isSource(DataFlow::Node source) { + source instanceof RemoteFlowSource + } + + override predicate isSink(DataFlow::Node sink) { + isRedirect(sink, _) + } +} + +from UrlRedirectionConfig config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink, source, sink, "Potential URL redirection from $@", source, "this source" \ No newline at end of file