MEAN stack applications (MongoDB, Express.js, AngularJS, and Node.js) are becoming increasingly popular as lightweight, easily deployable frameworks due to a vast ecosystem of middleware plugins and dependencies. But just how secure are these technologies?
Let’s examine some common vulnerabilities that are introduced either by using these components in their default configurations or due to common developer mistakes. Throughout this series, we will demonstrate each of these issues using an intentionally vulnerable MEAN Bug application, as well as provide mitigating techniques that developers can use to protect their applications from these issues. These articles focus on the security-related issues and assume that the reader has a basic understanding of the MEAN stack technologies.
The first piece of the technology stack that we will examine is the MongoDB database. This NoSQL database is immune to conventional SQL injection attacks, but is vulnerable to a similar attack called Query Selector Injection or NoSQL Injection which uses built-in logic operators to alter queries. To demonstrate, let’s look at the login form for our example application.
Figure 1: MEAN Bug login form
Using Burp Suite web proxy we have intercepted the login request and changed the POST pass parameter to pass[$ne]= where $ne is the MongoDB query operator ‘not equal to’.
Figure 2: Form parameter modified with HTTP proxy tool Burp Suite
When Express processes the x-www-form-urlencoded request body, this will be parsed into the object {user: ‘admin’, pass: {$ne: null} and passed to the MongoDB query in the code block below.
With the above payload, the query will match the first username that matches ‘admin’ with a password that is not equal to null, allowing us to authenticate to the application as an administrator without providing a valid password.
Figure 3: Bypassed authentication and accessed the application welcome page
If we attempt the same injection attack on the /secure/query API, we see that the request contains a JSON body which, unlike a simple POST body, is not vulnerable to attribute pollution when parsed by Express.
Figure 4: Initial request contains JSON body
However, if we change the Content-Type header to x-www-form-urlencoded and modify the body to contain our payload we can continue to use the Express parser to insert a query selector into the request object. This allows us to execute another Query Selector Injection attack and obtain all the invoices in the database.
Figure 5: Content-Type header and request body are modified to exploit Express parser
Perhaps the simplest way to mitigate query selector injection is to cast the values to a String before running the query. The vulnerable authentication query from the first example has been modified with the code block below.
If we re-submit the malicious request, the password will be matched against the String ‘$ne: null’ rather than evaluating the actual query operator ‘not equal to’. As a result, the authentication bypass attack no longer works.
Figure 6: Query selector injection attack failed after casting input to String
Alternatively, an input validation tool such as mongo-sanitize can be used to reject any request key beginning with the $ character used to denote query operators.
By default, MongoDB does not enforce authentication, meaning anyone can connect to and directly query the database. To further complicate this issue, MongoDB versions prior to 2.6.0 are bound to all interfaces by default. Whether the result of using an older instance with default configurations or explicitly binding a newer instance to a public interface, MongoDB databases are often exposed to the open internet. As demonstrated with our example application, we can connect directly to the MongoDB users database from an external system without any authentication using the Mongo Shell utility.
Figure 7: Accessing MongoDB users database directly with Mongo Shell
MongoDB also provides an optional HTTP and REST interface which, if enabled, exposes sensitive information about the databases and the underlying file system. These interfaces may be enabled in the configuration file as shown below or from the command line when starting the MongoDB instance. By default, they will bind to the database port plus 1000 (i.e., 28017).
Figure 8: HTTP interface exposes system and database information
Figure 9: Enabling the REST interface allows us to run commands such as ‘listDatabases’
To secure the MongoDB instance, the /etc/mongodb.conf file’s bind_ip, auth, httpinterface, and rest options should be configured to restrict access appropriately as demonstrated in the excerpt below.
As of January 2017, more than 40,000 MongoDB instances have been compromised by ransomware that exploits these servers’ insecure default configuration. You should take a few moments to ensure that your MongoDB instance is properly hardened so that it does not become a statistic.