MongoDB security – Injection attacks with php

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.

mongodb_1

mongodb_2

In the above script you can see the name of the database is securityand 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.

 

mongodb_3

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:

db.collection.findOne(query, projection)

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:

mongodb_4

Now let’s have a look at the source code:

mongodb_5

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?

http://localhost/mongo/inject.php?u_name=dummy’});return{something:1,something:2}}//&u_pass=dummy

 

This will break the query and return the desired parameter. Let’s check the output:

mongodb_6

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.

mongodb_7

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:

Screenshot_8

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.

Screenshot_9

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:

mongodb_10

Similarly we can have other username and password by changing the parameter inside the function db.users.find()[2],like

mongodb_11

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:

mongodb_12

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.

mongodb_13

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’]);

mongodb_14

Now if we try to break the query, it won’t prompt us with an error.

mongodb_15

References:

http://php.net/manual/en/mongocollection.find.php

https://media.blackhat.com/bh-us-11/Sullivan/BH_US_11_Sullivan_Server_Side_WP.pdf

 

  • I believe (or at least I hope) that in today’s world people aren’t using these kind of URLs construct, where you basically design the query in the URL. If you are doing that you should stop right away.
    But, to your point, you are totally right. Whoever write code that way will be exposed to more security holes that the ones you are mentioning in your post.

    • Sandeep

      This article demonstrate about the injection using PHP Mongo Driver. Mostly, I’ve seen some of people still using this type of coding, however I do believe developers are moving to frameworks, which gives you much better security for this type of injection. This post is actually enlightening, how dangerous it could be, if you use external resources directly with MongoDB Driver.

    • Mohammed Gad

      the problem isn’t the URL design even if he uses post instead of get it can be intercepted and manipulated too.