Black Box Meteor - Method Auditing

Written by Pete Corey on Apr 15, 2015.

When using Meteor methods, a surprising amount of information can be passed down to the client. Let’s considering the following method definitions:

Meteor.methods({
    sharedMethod: function() {
        console.log('This is a shared method.');
        if (Meteor.isServer) {
            console.log('This is behind a server guard.');
            Meteor.call('serverMethod');
        }
    }
});

if (Meteor.isServer) {
    Meteor.methods({
        serverMethod: function() {
            console.log('This is a server method.');
        }
    });
    Meteor.methods({
        hiddenMethod: function() {
            console.log('This is a hidden method.');
        }
    });
}

With these methods set up, open your browser’s console and take a look at the method handlers exposed to the client:

Meteor.connection._methodHandlers

Along with a few others, you’ll see the handler for sharedMethod. You won’t see serverMethod or hiddenMethod because both of these methods were defined entirely behind a server guard.

Take a look at the source of sharedMethod:

Meteor.connection._methodHandlers.sharedMethod.toString();

You’ll notice that you can see all of the method’s contents, including any permission checks and validation that may or may not be taking place. You can see the call to serverMethod! It’s important to realize that unless you’re being careful, even server guarded blocks will be passed down to the client within client visible method handlers.

All methods can be called from the client, even methods that the client should have no knowledge of:

Meteor.call(‘sharedMethod’, ...);
Meteor.call(‘serverMethod’, ...);
Meteor.call(‘hiddenMethod’, ...);

It’s not enough to try to hide your methods on your server. Always be sure to do proper validation, sanitation and authentication before taking any action in a method.

I highly recommend taking a look at Sacha Greif’s three part latency compensation series (An Introduction to Latency Compensation, Advanced Latency Compensation, and Two-Tiered Methods) over at Discover Meteor to better understand how to use and protect your Meteor methods.

NoSQL Injection - Or, Always Check Your Arguments!

Written by Pete Corey on Apr 6, 2015.

Since Meteor only supports the fantastic MongoDB, we no longer have to worry about the ever present threat of SQL injection. Gone are the days of query parameters and ORMs. Right? Wrong!

While not as well-known or potentially as dangerous as SQL injection, as MongoDB developers, we still need to be ever vigilant against NoSQL injection.

SQL injection usually occurs when SQL query strings are constructed by concatenating or directly inserting unescaped user input into the query. This gives the malicious user (mostly) free reign to modify the command however they see fit, or potentially run additional commands against your database.

MongoDB queries take the form of JSON/BSON objects, not strings. We should be safe from injection, right? To an extent, yes. But let’s take a look at a very simple example. Suppose we have a Meteor publication that takes an argument and passes that argument through to a Collection query:

Meteor.publish('injectMe', function(foo) {
    return SensitiveDocuments.find({
        foo: foo
    });
});

Let’s say the client subscribes to this publication and passes in some piece of user information (foo). Ideally, only the sensitive documents related to that user’s foo will be returned by the subscription.

In this case, foo is intended to be a string. But what happens if a malicious client opens their browser console and makes this subscription:

Meteor.subscribe('injectMe', {$gte: ''});

Suddenly, all of the sensitive documents for every user will be served to the malicious user. All of the sensitive documents in the database will have a value of foo that is ordinally greater than or equal to an empty string.

To guard against this, always check each of your arguments:

Meteor.publish('injectMe', function(foo) {
    check(foo, String);
    return SensitiveDocuments.find({
        foo: foo
    });
});

This check will assert that foo is a String. If not, a Match.Error exception is thrown.

To ensure that every argument sent to your methods and publications is being checked, you can add the audit-argument-checks package to your project:

meteor add audit-argument-checks

While the consequences of this aren’t nearly as far reaching as those of SQL injection, it’s still something to be aware of when you’re developing your Meteor publications and methods.

Black Box Meteor - Triple Brace XSS

Written by Pete Corey on Apr 3, 2015.

Meteor is an incredibly interesting framework from a security perspective. Due to the unique way in which it deals with it’s client/server separation, most of the information and functionality passed to the client is presented in a very uniform, organized way. From a black box security testing perspective, this can make life much easier!

We’ll start our black box adventure by searching for potential Cross Site Scripting (XSS) and/or Stored XSS attack vectors. One potential attack vector is the use of triple brace tags. Allowing un-sanitized user input into these raw tags can potentially let malicious users execute javascript on other clients’ machines. This is bad!

Finding Triple Braces

Thanks to the Spacebars compiler, we have all of the information we need to find templates that make use of triple braces.

Let’s take a tour of the template information given to each client. All of the templates used in the application live in the Template object. We can get a list of template names (along with some other Template specific object keys, such as instance, etc…) by grabbing the keys of the object:

Object.keys(Template);

If you’re interested in a particular template, you can drill into its renderFunction and access it directly, or turn it into a string and peruse the source:

Template.interestingTemplate.renderFunction.toString();

You’ll notice that the renderFunction holds the result of the Spacebars compilation process. The DOM is represented as HTMLjs objects, interspersed with Spacebars objects. In our case, the triple braces we’re looking for are transformed into calls to Spacebars.makeRaw.

Using this knowledge, we can easily find all of the templates that use triple braces throughout the application:

Object.keys(Template).filter(function(key){
    return Template[key] &&
           Template[key].renderFunction &&
           Template[key].renderFunction.toString().indexOf('Spacebars.makeRaw') > -1;
});

We could take this a step further by doing some monkey patching. Let’s replace the Spacebars.makeRaw method with a method that adds a data attribute to the first element passed into it:

Spacebars._makeRaw = Spacebars.makeRaw;
Spacebars.makeRaw = function (value) {
    function injectDataAttr() {
        var idx = value.indexOf('>');
        if (idx == -1) {
            return value;
        }
        return value.substr(0, idx) +
               ' data-make-raw' +
               value.substr(idx);
    }
    if (value == null)
        return null;
    else if (value instanceof HTML.Raw) {
        return HTML.Raw(injectDataAttr(value.value));
    }
    else {
        return HTML.Raw(injectDataAttr(value));
    }
};

You can then add a CSS rule to outline each raw element:

[data-make-raw] {
    outline: 1px solid tomato;
}

Or do it from the console:

var style = document.createElement("style");
style.appendChild(document.createTextNode(""));
document.head.appendChild(style);
style.sheet.insertRule('[data-make-raw] { outline: 1px solid tomato; }',0);

Here’s an example running against Telescope:

Telescope example

In this case I would make absolutely sure that the post title and each of the comments are being properly sanitized before being stored in the database and rendered on the client. If we miss either of these, we’re looking at a Stored XSS vulnerability!

What Does It All Mean?

This is just a tool to point you in the direction of potential vulnerabilities. It will show you all uses of triple braces throughout your application, but not all triple braces are bad! There are many valid uses of these raw tags, but you need to ensure that the content being rendered is truly safe. Always be sure to sanitize any user input that may find its way into a triple brace tag.

Also keep in mind that there are other XSS attack vectors such as the use of Spacebars.SafeString, dynamic attributes, and even within attribute values on certain attributes like href and onclick, to name a few.

Always be vigilant! Never trust user input!