Before we move on to the MongoDb injections, we must understand what MongoDb exactly is and why we prefer it over other databases. As MongoDb does not use SQL people assumed it is not vulnerable to any kind of injection attacks. But believe me, no one is born with inbuilt security aspects. We have to implement some logic in order to prevent attacks.
What is MongoDb?
In short MongoDb is an open-source database developed by MongoDb Inc., which stores data in JSON-like documents that can vary in structure. Here related information is stored together for fast query access through the MongoDb query language.
Why to use MongoDb?
Just because everyone wants quick results of the queries,MongoDb is most popular. It gives very high performance (1000 millionsquries/sec). Another reason why MongoDb is more popular is because it excels in many use cases where relational databases aren’t a good fit.For example,applications with unstructured, semi-structured and polymorphic data, as well as applications with large scalability requirements or multi-data center deployments.
Stop! Before go further, If you run any open source application. We are providing a free PenTest for open source projects. Submit your application for evaluation here.
Let’s walk through the injections
In the first case we have a PHP script which shows the username and password corresponding to a particular id.
In the above script you can see the name of the database is security, and the name of collection is users. We ontain the u_id parameter from the GET method, and then pass it to an array which gives us the associated results.Sounds good? Let’s try to put some comparison operators with the array.
Oops..!! It dumped the entire database for us. Can you figure out what went wrong with it? This happened because the input http://localhost/mongo/show.php?u_id[$ne]=2
created the following MongoDb query.
$qry= array(“id” => array(“$ne” => 2))
So accordingly it displays all the results except id=2 which we see in snapshot 1.
Let’s consider another case where the script does the same work as earlier, but in this case we’ll create MongoDb query with findOne method.
We’ll first have a quick look at the working of the findOne method. This method has the following syntax:
This returns the document that satisfies the specified query criteria. For example if we need to find the result associated with id=2, we will fire the following command:
Now let’s have a look at the source code:
Here the key point is to somehow break the query and then fix it again. Can you guess what will happen if we typed the following query?
This will break the query and return the desired parameter. Let’s check the output:
Did you notice it gave us two errors, just because we wanted to access two parameters which really don’t exist? Indirectly this error shows that username and password are the parameters in database, and that’s what we want.
As soon as we type the correct parameter instead of something, the error is removed.
Now let’s say we want to find the name of database. In MongoDb,db.getName() method is used to find the name of the database. So the query will be:
In order to dump the database,we first need to find the name of the collections.The db.getCollectionNames()method is used to find the name of collections in MongoDb.
So, till now we have obtained the name of database and collections. What remains is to find the data inside the users collections which can be done as follows:
Similarly we can have other username and password by changing the parameter inside the function db.users.find(),like
Now that you’re familiar with MongoDb injections, probably you would want to know about the prevention of this kind of injection.
Let’s consider the first case where we pass the parameter to an array. To prevent this injection, we somehow need to stop the execution of comparison operators in the array.So, one of its solution is to use implode() function in the following way:
The implode()function returns a string from the elements of an array. Hence we get only one result corresponding to that particular id instead of all the results.
In the second case we can use addslashes() method so that the query cannot be broken by the attacker. However using regular expression to replace special symbols would be a great idea. You can use the following Regex:
$u_name =preg_replace(‘/[^a-z0-9]/i’, ‘\’, $_GET[‘u_name’]);
Now if we try to break the query, it won’t prompt us with an error.