This is the second part of a two-part series on NoSQL injections. Last time, we covered the anatomy of a NoSQL injection, as well as how to mitigate it. In this post, we will look at specific injection attack types, namely Server-Side JavaScript and Blind NoSQL injections.

In our last article, we looked at how malicious parties could run queries against a NoSQL database, as well as how to mitigate such risks. In this article, we will take a look at two more specific types of injection attacks against NoSQL databases.

Server-Side JavaScript Injections on NoSQL Databases

Server-side JavaScript (SSJS) Injections occur when a server-side component allows the attacker to execute JavaScript code in the server context. Sometimes, this is allowed to provide developers with extended functionality. However, in the wrong hands, this capability lets malicious parties provide untrusted data that are then interpreted and executed by the server.

Some of the more commonly used functions for server-side JavaScript injection attacks include:

  • eval()
  • setTimeout()
  • setInterval()
  • Function()

All of these functions will parse arguments originating from a user-controlled source of input data.

SSJS: An Example

MongoDB’s Evaluation Query operator $where allows you to match documents when they satisfy a JavaScript expression. For example, there’s:

db.users.find( { $where: function() { return (this.country == ‘VA’); }});

which can be shortened to

db.users.find( { $where: this.country == ‘IL’ }});

Whenever this query executes, MongoDB finds and returns all of the user’s collection documents where their country field equals the string VA.

This is risky, and if you allow users to pass unsanitized parameters to the evaluated JavaScript expression for the $where operator, you’ve introduced a security vulnerability. To see how a malicious attacker could exploit this vulnerability, the following ExpressJS sample app defines an HTTP GET call to the /userCountries API endpoint (though this would also work with POST and PUT calls), which then executes a MongoDB injection with the $where operator:

app.get(‘/userCountries’, function(req, res) {

  var country = req.query.country;
  var searchCriteria = “this.country == “ + “‘“ + country + “‘“;
  users.find({
    $where: searchCriteria
    }).toArray(function(err, response) {
    res.render(‘users’, { users: response });
  });
});

The searchCriteria variable builds the where expression based on user input, so the exact query looks like the following:

$where: “this.country == ‘VA’”

You can see how this query resembles a traditional SQL injection. Because the $where operator evaluates JavaScript, the example above showing the combining of user input with a MongoDB query results in the following problematic scenario:

  1. The attacker sends an HTTP GET request that satisfies the $where operator. The request provides text to the Boolean expression and closes the expression with a single quotation mark.
  2. With the string expression terminated, the attacker can add any valid JavaScript code to the request. With an additional single quote to close the expression, everything gets concatenated:
curl “http://localhost:31337/user?country=VA';while(true)\{\};'”

This results in the following $where operator expression:

$where: “this.country == ‘VA’;while(true){};’’”

This expression triggers a Denial of Service (DoS) attack on the MongoDB service. While the attacker hasn’t chosen to exploit Node.js here (and it can, therefore, continue to serve requests), additional requests to the Node.js server requiring MongoDB fails.

At this point, MongoDB is using up 100% of the CPU’s resources in an infinite loop that ends only the watchdogs and timers kick in.

Mitigating SSJS Injection Attacks

If you’re working with MongoDB, you should probably avoid using the $where operator if at all possible. However, the following are general, best practice guidelines on avoiding and mitigating NoSQL injection attacks:

  1. **Sanitize and validate user input: **Do not allow input originating from users to be used without sanitization and validation; make sure that what you’re allowing and expecting matches what the user has provided
  2. **Use prepared statements: **Prepared statements have been used to prevent SQL injection attacks, and similarly, they can be used in NoSQL situations as well. Prepared statements allow you to secure the data
  3. Avoid using JavaScript functions to parse user input: Avoid using eval(), setTimeout(), setInterval(), or Function()to parse user-provided input

Blind NoSQL Injections

The purpose of a blind injection attack is to get as much information from the database as possible; even if a direct injection fails, the attacker uses the information gleaned to refine and create new queries. Over time, the attacker learns more and more about the database’s structure and its contents.

One variant of a blind noSQL injection exists in MongoDB and allows malicious parties to use operators, including $regex, which helps them gather information by varying the regular expressions sent as input to the database.

#javascript #security #nosql #shiftleft #application-security

Mitigating NoSQL Injection Attacks: Part 2
1.25 GEEK