Code Monkey home page Code Monkey logo

codeql-javascript-unsafe-jquery-plugin's Introduction

codeql-javascript-unsafe-jquery-plugin's People

Contributors

castarco avatar xcorail avatar

Watchers

 avatar  avatar

codeql-javascript-unsafe-jquery-plugin's Issues

Step 10 - Putting it all together: the taint tracking query

Step 10: Putting it all together

Great! you made it to the final step ๐ŸŽ‰

We have now identified

  • (a) places in the program which receive jQuery plugin options, and which may be considered as sources of untrusted data, and
  • (b) places in the program which are passed to the jQuery $ function and may be interpreted as HTML, that we consider as sinks, in the sense that they will perform actions with the data they receive. We don't want these sinks to receive untrusted data.

We now want to tie these two together to ask: does the untrusted data from a jQuery plugin option ever flow to the potentially unsafe $ call?

This is also a data flow problem. However, it is larger in scope that the problems we have tackled so far, because the plugin options and the $ call may be in different functions. We call this a global data flow problem.

๐Ÿ“– You can learn more about data flow analysis in JavaScript by reading the documentation and this cheat sheet.

In this section we will create a path problem query capable of looking for global data flow, by populating this template:

/**
 * @name Cross-site scripting vulnerable plugin
 * @kind path-problem
 * @id js/xss-unsafe-plugin
 */
import javascript
import DataFlow::PathGraph

class Config extends TaintTracking::Configuration {
  Config() { this = "Config" }
  override predicate isSource(DataFlow::Node source) {
    /** TODO fill me in from step 9 **/ 
  }
  override predicate isSink(DataFlow::Node sink) {
    sink = /** TODO fill me in from step 5 **/
  }
}

from Config config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink, source, sink, "Potential XSS vulnerability in plugin."

In this template, we just have to define what are the sources and the sinks that we want to consider, and the CodeQL global data flow library will give us all the paths where data can flow from these sources to these sinks, using the predicate hasFlowPath that holds true when tainted data from a given source flows to a sink.

Step 7 - Finding jQuery plugin options: plugins

Step 7: Finding the jQuery plugins

In this step we want to detect the jQuery plugin assigned to our property,
so basically the right hand side of the assignment in our previous example:

$.fn.copyText = function() { ... } // this function is a jQuery plugin

But there might be some variation in how this code is written. For example, we might see intermediate assignments to local variables:

let fn = $.fn
let f = function() { ... } // this function is a jQuery plugin
fn.copyText = f

The use of intermediate variables and nested expressions are typical source code examples that require use of local data flow analysis to detect our pattern.

Step 6 - Finding jQuery plugin options: property reads

Step 6: Finding jQuery plugin options

jQuery plugins are usually defined by assigning a value to a property of the $.fn object:

$.fn.copyText = function() { ... } // this function is a jQuery plugin

In the following steps, we'll find such plugins, and their options. We'll find

  • where the property $.fn is read
  • the functions that are assigned to properties of $.fn
  • the option parameters of these functions

Step 5 - Using the jquery predicate

Step 5: Using the jQuery library

So far we have looked for the function name $. Are there other ways of calling the jQuery $ function? Perhaps the CodeQL library can handle these for us?

The CodeQL standard library for JavaScript has a built-in predicate jquery() to describe references to $.
Calling the predicate jquery() returns all values that refer to the $ function, and chaining this call with getACall(), will give you all calls to this function.

Step 3 - Your first query

Step 3: Finding calls to the jQuery $ function

You will now run a simple CodeQL query, to understand its basic concepts and get familiar with your IDE.

โŒจ๏ธ Activity: Run a CodeQL query

  1. Edit the file calls-to-dollar.ql with the following contents:

    import javascript
    
    from CallExpr dollarCall
    where dollarCall.getCalleeName() = "$"
    select dollarCall

    Don't copy / paste this code, but instead type it slowly. You will see the CodeQL auto-complete suggestions in your IDE as you type.

    • After typing from and the first letters of CallExpr, the IDE will propose a list of available classes from the CodeQL library for JavaScript. This is a good way to discover what classes are available to represent standard patterns in the source code.
    • After typing where dollarCall. the IDE will propose a list of available predicates that you can call on the variable dollarCall.
    • Type the first letters of getCalleeName() to narrow down the list.
    • Move your cursor to a predicate name in the list to see its documentation. This is a good way to discover what predicates are available and what they mean.
    • A function call is called a CallExpr in the CodeQL JavaScript library.
    • We use the = operator to assert that two values are equal.
  2. Run this query: Right-click on the query editor, then click CodeQL: Run Query.

  3. Inspect the results appearing in the results panel. Click on the result hyperlinks to navigate to the corresponding locations in the Bootstrap code. Do you understand what this query does? You probably guessed it! This query finds all calls to the function named $.

Now it's time to submit your query. You will have 2 choices to do that, and we'll explain both of them in the comments below. Once you have chosen your method, submit your answer!

Read carefully: you will need to follow the same steps to submit your answers to later steps. You can always come back to this issue later to check the submission instructions.

Step 9 - Detecting untrusted data flow sources

Step 9: Detecting the sources

We have now identified places in the program which receive jQuery plugin options, and which may be considered as sources of untrusted data. In this step we'll create a predicate that will hold true if a DataFlow::Node is such a source. This predicate will be helpful for our last query.

Step 4 - Understanding the query, binding objects

Step 4: Anatomy of a query

Now let's analyze what you have written. A CodeQL query has the following basic structure:

import /* ... path to some CodeQL libraries ... */

from /* ... variable declarations ... */
where /* ... logical formulas that say something about the variables ... */
select /* ... expressions to output ... */

The from/where/select part is the query clause: it describes what we are trying to find in the source code.

Let's look closer at the query we wrote in the previous step.

Show the query
  import javascript

  from CallExpr dollarCall
  where dollarCall.getCalleeName() = "$"
  select dollarCall

Imports

At the top of the query is import javascript. This is an import statement . It brings into scope the standard CodeQL library that models JavaScript/TypeScript code, allowing us to use its features in our query. We'll use this library in every query, and in later steps we'll also use some more specialized libraries.

Classes

In the from section, there is a declaration CallExpr dollarCall. Here we declare a variable named dollarCall which has the type CallExpr. CallExpr is a class declared in the standard library (you can jump to the definition using F12). A class represents a collection of values, in this case the collection of all function calls.

Predicates

Now look at the expression dollarCall.getCalleeName() in the where section. Here we call the predicate getCalleeName on the variable dollarCall of type CallExpr. Predicates are the building blocks of a query: they express logical properties that we want to hold. Some predicates return results (like getCalleeName) , and some predicates do not (they just assert that a property must be true).

So far your query finds all functions with the name $. It does this by asserting that the result of dollarCall.getCalleeName() is equal to the string "$". But what we want actually is to find the first argument of each of these calls.

One way to do this is to declare two variables: one to represent function calls, and one to represent call arguments. Then you will have to create a relationship between these variables in the where section, so that they are restricted to the first arguments of calls to functions named $.

Set up your IDE

Step 2: Setup your environment

We will use the CodeQL extension for Visual Studio Code. You will take advantage of IDE features like auto-complete, contextual help and jump-to-definition.

Don't worry, you'll do this setup only once, and you'll be able to use it for future CodeQL development.

Follow the instructions below.

Welcome!

Welcome to the CodeQL Unsafe JQuery course!

We created this course to help you quickly learn CodeQL, our query language and engine for code analysis. The goal is to find several cross-site scripting (XSS) vulnerabilities in the open-source software known as Bootstrap, using CodeQL and its libraries for analyzing JavaScript code. To find the real vulnerabilities, you'll need to write a sequence of queries, making them more precise at each step of the course.

More detail

jQuery is an extremely popular, but old, open source JavaScript library designed to simplify things like HTML document traversal and manipulation, event handling, animation, and Ajax. The jQuery library supports modular plugins to extend its capabilities. Bootstrap is another popular JavaScript library, which has used jQuery's plugin mechanism extensively. However, the jQuery plugins inside Bootstrap used to be implemented in an unsafe way that could make the users of Bootstrap vulnerable to cross-site scripting (XSS) attacks. This is when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user.

Four such vulnerabilities in Bootstrap jQuery plugins were fixed in the pull request https://github.com/twbs/bootstrap/pull/27047, and each was assigned a CVE.

The core mistake in these plugins was the use of the omnipotent jQuery $ function to process the options that were passed to the plugin. For example, consider the following snippet from a simple jQuery plugin:

let text = $(options.textSrcSelector).text();

This plugin decides which HTML element to read text from by evaluating options.textSrcSelector as a CSS-selector, or that is the intention at least. The problem in this example is that $(options.textSrcSelector) will execute JavaScript code instead if the value of options.textSrcSelector is a string like "<img src=x onerror=alert(1)>". The values in options cannot always be trusted.

In security terminology, jQuery plugin options are a source of user input, and the argument of $ is an XSS sink.

The pull request linked above shows one approach to making such plugins safer: use a more specialized, safer function like $(document).find instead of $.

let text = $(document).find(options.textSrcSelector).text();

In this course, we will use CodeQL to analyze the source code of Bootstrap, taken from before these vulnerabilities were patched, and identify the vulnerabilities.

Step 1: Know where to get help!

Bookmark these useful documentation links:

If you get stuck during this course and need some help, the best place to ask for help is on the GitHub Security Lab Slack. Request an invitation from the Security Lab Get Involved page and ask in the channel #codeql-writing. You can also visit our forum to search for possible answers.

There are also sample solutions in the course repository, but please try to solve the tasks on your own first!

Hope this is exciting! Please close this issue now, and continue to the next step.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.